mui / material-ui

Material UI: Comprehensive React component library that implements Google's Material Design. Free forever.
https://mui.com/material-ui/
MIT License
93.86k stars 32.26k forks source link

Safari and ios bug with Next.js: Warning: Prop `className` did not match. Server: ... #14159

Closed Victorkangsh closed 5 years ago

Victorkangsh commented 5 years ago

Safari and ios bug: Warning: Prop className did not match. Server: ...

This is very strange, the page performs well on chrome, but on Safari and all browsers (even chrome) under ios have lost some css. The error message is:Warning: Prop className did not match. Server: ...

Expected Behavior 🤔

ios platfrom and safari work success.

Current Behavior 😯

on Chrome:

2019-01-12 5 27 02

on Safafi:

2019-01-12 5 27 46

Env

macOS: mojava nextjs: latest material-ui: latest

oliviertassinari commented 5 years ago

@Victorkangsh I would encourage you to isolate the source of the issue using dichotomy. Remove as much as possible components from your React tree while still seeing this warning. Once you find the culprit component, fix it. I'm +90% confident it's an issue with your implementation, for instance using /iPad|iPhone|iPod/.test(navigator.userAgent) logic incorrectly.

Alternatively, you can upgrade to @material-ui/styles were we use a hash-based class name, making this class name warning go away, you should see a new one, better correlated the true source of the problem.

Victorkangsh commented 5 years ago

@oliviertassinari Many thanks, I resolved by dichotomy. The reason is Safari and ios can't solve duplicate named jss. And the @material-ui/styles looks awesome, I will try it later.

oliviertassinari commented 5 years ago

@Victorkangsh Could you provide more detail on the issue? I don't understand what you mean by duplicated named jss. Thank you!

Victorkangsh commented 5 years ago

ok, but I'm not sure where is the problem happened exactly.

err jss:

import aaa from '../aaa.jsx';
import bbb '../bbb.jsx';

const boxStyle = {
  ...aaa,
  ...bbb,
  box: {
    height: '20px',
    zIndex: 2
  },
......

I just flaten it by copy and remove duplicated css name, maybe aaahave aaa1andbox:

const boxStyle = {
  aaa1: {
    weight: '20px'
  },
  bbb1: {
    color: '#333'
  },
  box: {
    height: '20px',
    zIndex: 2
  },

It worked. Looks so strange...

oliviertassinari commented 5 years ago

Yes, It's weird.

cc @kof (I think that I will keep pinging you on styles related subjects if you don't mind. You don't have to answer, you can use it as a data acquisition channel.)

kof commented 5 years ago

The reason is Safari and ios can't solve duplicate named jss.

@Victorkangsh I am not sure what you mean here.

@oliviertassinari yes, please keep pinging me on such issues!

kof commented 5 years ago

@Victorkangsh if you are talking about having duplicate property names in objects like this:

{
  a: ...,
  a: ...
}

then this is disallowed by spec in JS and the last property will override the first one. This is consistent across any browser.

I would advise you to log your styles object and see what is getting passed to JSS. You will most likely see a problem there.

Victorkangsh commented 5 years ago

@kof My first statement was wrong, I tested it again. The problem is not duplicate naming, it should be nested import jss will cause css secondary injection in nextjs(I'm not sure), which is no problem in chrome, but it seems to prevent this behavior in safari and ios. When using hmr during development, the page will be automatically refreshed after changing some things, and Safari's css will be fine. This should not be a problem with material-ui, but some problems with nextjs. Another application I developed with react has no similar errors.

kof commented 5 years ago

@Victorkangsh we will need a reproduction

Victorkangsh commented 5 years ago
// index.js
import aaa from 'aaa.jsx'
class IndexPage extends React.Component {
  render() {
    const { classes } = this.props;
    return (
      <React.Fragment>
         <p className={classes.test1}>11111</p>
         <p className={classes.test2}>11111</p>
      </React.Fragment>
     )
  }
}
export default withStyles(aaa)(IndexPage);

//aaa.jsx
import bbb from 'bbb.jsx'
export const aaa = {
    ...bbb,
    test1:{ color: '#blue' }
}

// bbb.jsx
export const bbb = {
  test2:{ color: '#red' }
}

In React or Nextjs&chrome it worked, but in Nextjs &Safari/ios the test2 will lost. And when you change it:

//aaa.jsx
export const aaa = {
    test2:{ color: '#red' },
    test1:{ color: '#blue' }
}

it worked fine. cc @timneutkens

jimmiebtlr commented 5 years ago

I'm actually running into the same issue on chrome atm with next.js.

jimmiebtlr commented 5 years ago

Prop className did not match. Server: "MuiTypography-root-128 MuiTypography-h5-144" Client: "MuiTypography-root-127 MuiTypography-h5-143"

Assuming the number at the end of className is incremented each time a class is needed, it seems the server is using extra class names. (in a fairly minimal example the server is 1 greater than client).

jimmiebtlr commented 5 years ago

The number difference between server and client styles goes up as I pass the classes prop to mui components with style objects instead of className={classNames(classes.style...

But only makes it down to 1 difference when I remove all instances of classes.

oliviertassinari commented 5 years ago

@jimmiebtlr Have a look at our next.js examples. They should be free from this issue.

jimmiebtlr commented 5 years ago

Sorry, may not be same issue as op

Minimal reproduction though https://github.com/jimmiebtlr/nextjs-materialui-ssr-bug-example

jimmiebtlr commented 5 years ago

Guessing this may be a next build issue rather than a mui issue.

Basically directly exporting a mui module from a file and using that elsewhere causes class names not to match up.

oliviertassinari commented 5 years ago

Basically directly exporting a mui module from a file and using that elsewhere causes class names not to match up.

@jimmiebtlr You can't import the components directly. You need to follow the Next.js integration example we host: https://github.com/mui-org/material-ui/tree/master/examples/nextjs.

killianhuyghe commented 4 years ago

Just had this issue and I can confirm it was due to duplicate property names in my style object (passed to makeStyles) as mentioned by @kof .

I didn't notice it easily because I had many different properties:

{
  a: ...
  b: ...
  c: ...
  ...
  a: ...
}

Not sure why this happens, but on Safari, it looks like the duplicate property increments the jss numbering, making every style number off by one (.jss1 becomes .jss2 and so on). This completely breaks the style of the component.