question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Class name hydration mismatch in server and client, (Warning: Prop `className` did not match Server and Client)

See original GitHub issue

I don’t know my issue is a bug or just a support term or just a configuration mismach, but I spend much time, Not happy go lucky writing here to somebody settle my issue. no!

I searched for 3 days, Even just sleep about 10 hours in this 3 days, try many ways, even I use Gitter but no one answer me, I see issues #10982 and #11506 and many Stack Overflow question and answers but I couldn’t fix my issue and didn’t find right way.

Absolutely I read and read many times the Material-UI Docs but I exactly did what the Docs said.

At last, I see class name hydration mismatch in server and client, 😞 this warning:

Warning: Prop `className` did not match. Server: "MuiFormLabel-root-134 MuiInputLabel-root-129 MuiInputLabel-formControl-130 MuiInputLabel-animated-133" Client: "MuiFormLabel-root-10 MuiInputLabel-root-5 MuiInputLabel-formControl-6 MuiInputLabel-animated-9"

I swear I tried many ways and searched a lot. I’m using Material-UI version 1.2.1.

This is my Index component as a root component:

    import React, {Component} from 'react';
    import Helmet from 'react-helmet';
    import styles from 'StylesRoot/styles.pcss';
    import TextField from '@material-ui/core/TextField';

    export default class App extends Component {

        render() {
            return (
                <div className={styles['root-wrapper']}>
                    <Helmet
                        htmlAttributes={{lang: 'fa', amp: undefined}}
                        bodyAttributes={{dir: 'rtl'}}
                        titleTemplate='اسکن - %s'
                        titleAttributes={{itemprop: 'name', lang: 'fa'}}
                        meta={[
                            {name: 'description', content: 'صفحه اتصال اعضاء'},
                            {name: 'viewport', content: 'width=device-width, initial-scale=1'},
                        ]}
                        link={[{rel: 'stylesheet', href: '/dist/styles.css'}]}
                    />
                    <TextField label='test' helperText='help'/>
                </div>
            );
        };
    }

Here below you can see my server.jsx and client.jsx:

    //--------------------------------------------client.jsx
    import React from 'react';
    import {hydrate} from 'react-dom';
    import {BrowserRouter} from 'react-router-dom';
    import {MuiThemeProvider, createMuiTheme} from '@material-ui/core/styles';
    import {lightBlue, red} from '@material-ui/core/colors';
    import Index from './app/index';
    import RTL from './app/public/rtl';
    
    const theme = createMuiTheme({
        palette: {
            primary: lightBlue,
            accent: red,
            type: 'light',
        },
        direction: 'rtl',
    });
    
    class Main extends React.Component {
        // Remove the server-side injected CSS.
        componentDidMount() {
            const jssStyles = document.getElementById('jss-server-side');
            if (jssStyles && jssStyles.parentNode) {
                jssStyles.parentNode.removeChild(jssStyles);
            }
        }
    
        render() {
            return (
                <BrowserRouter>
                    <Index {...this.props}/>
                </BrowserRouter>
            );
        }
    }
    
    hydrate((
        <RTL>
            <MuiThemeProvider theme={theme}>
                <Main/>
            </MuiThemeProvider>
        </RTL>
    ), document.getElementById('root'));



    //--------------------------------------------server.jsx
    import React from 'react';
    import {renderToString} from 'react-dom/server';
    import {SheetsRegistry} from 'react-jss/lib/jss';
    import JssProvider from 'react-jss/lib/JssProvider';
    import {StaticRouter} from 'react-router-dom';
    import {Helmet} from "react-helmet";
    import {MuiThemeProvider, createMuiTheme, createGenerateClassName} from '@material-ui/core/styles';
    import {red, lightBlue} from '@material-ui/core/colors';
    import Template from './app/template';
    import Index from './app/index';
    import RTL from './app/public/rtl';
    
    export default function serverRenderer({clientStats, serverStats}) {
        return (req, res, next) => {
            const context = {};
            const sheetsRegistry = new SheetsRegistry();
            const theme = createMuiTheme({
                palette: {
                    primary: lightBlue,
                    accent: red,
                    type: 'light',
                },
                direction: 'rtl',
            });
            const generateClassName = createGenerateClassName();
            const markup = renderToString(
                <JssProvider registry={sheetsRegistry} generateClassName={generateClassName}>
                    <RTL>
                        <MuiThemeProvider theme={theme} sheetsManager={new Map()}>
                            <StaticRouter location={req.url} context={context}>
                                <Index/>
                            </StaticRouter>
                        </MuiThemeProvider>
                    </RTL>
                </JssProvider>
            );
            const helmet = Helmet.renderStatic();
    
            const jss = sheetsRegistry.toString();
    
            res.status(200).send(Template({
                markup: markup,
                helmet: helmet,
                jss: jss,
            }));
        };
    }

So now it’s needed to template.jsx:

    export default ({ markup, helmet, jss }) => {
        return `<!DOCTYPE html>
                <html ${helmet.htmlAttributes.toString()}>
                    <head>
                        ${helmet.title.toString()}
                        ${helmet.meta.toString()}					
                        ${helmet.link.toString()}
                        <style id='jss-server-side'>${jss}</style>									
                    </head>
                    <body ${helmet.bodyAttributes.toString()}>
                        <div id='root'>${markup}</div>
                        <script src='/dist/client.js' async></script>
                    </body>
                </html>`;
    };

Ok, Now it is possible that this question is asked What is RTL? and Why you wrap MuiThemeProvider inside it in both server and client?

So first see RTL component:

    import React from 'react';
    import {create} from 'jss';
    import rtl from 'jss-rtl';
    import JssProvider from 'react-jss/lib/JssProvider';
    import {createGenerateClassName, jssPreset} from '@material-ui/core/styles';
    
    const jss = create({plugins: [...jssPreset().plugins, rtl()]});
    
    const generateClassName = createGenerateClassName();
    
    export default props => (
        <JssProvider jss={jss} generateClassName={generateClassName}>
            {props.children}
        </JssProvider>
    );

I saw it in Material-UI Docs and I believe the documentation is a little poor and could be improved. I asked myself, Why documentation pass a props.children for this function? and I guess maybe this function should wrap something. so I try many shapes and it works. but in the first call in browser after build. when I refresh the browser then the warning appears 😞 and I see this damn shape:

image

Surely I wanna see below shape, but I see it just once after build:

image

I don’t know what is going wrong. I put this question on Stack Overflow too. And upload a mini repo for this issue, for seeing my issue just pull, and run npm install then num run dev. the project is accessible on localhost:4000

If I break some of your rules please forgive me but guide me how I can settle this issue.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:2
  • Comments:23 (8 by maintainers)

github_iconTop GitHub Comments

10reactions
oliviertassinaricommented, Jul 20, 2018

@amerllica Reviewing the information provided, the root of your issue isn’t with right-to-left but with server-side rendering on its own. I would encourage you to simplify the problem as much as possible: for instance, removing the right-to-left handling in the app to better understand what’s going on. You most likely fall into this part: https://material-ui.com/guides/server-rendering/#css-works-on-only-on-first-load.

@basicfu For people who just want to get it working without addressing the root issue, we have a flag for that: https://material-ui.com/customization/css-in-js/#global-css

9reactions
up209dcommented, Aug 13, 2018

@nosykretts : I think the problem is not from next, jss or mui. Your wrapping strategy is problematic as you used MainLayout to wrap Index, I would not make MainLayout wrap the Index cuz

App > Index > Anything Content Component

So App is used for Router + Provider > Index is main case Page Component returned by Router > MainLayout is a Layout Component along with Header & Footer Components

_app.js

<MainLayout>
  <Component pageContext={this.pageContext} {...pageProps} />
</MainLayout> 

// Component here is supposed to be Index, so you need to leave it alone as
<Component pageContext={this.pageContext} {...pageProps} />  

index.js

  render() {
    const { classes } = this.props;
    return (
      <MainLayout className={classes.root}>
        <Typography variant="display1" gutterBottom>
          Material-UI
        </Typography>
        <TroubleButton />
      </MainLayout>
    );
  }
Read more comments on GitHub >

github_iconTop Results From Across the Web

Class name hydration mismatch in server and client, (Warning ...
At last, I see class name hydration mismatch in server and client, this warning: Warning: Prop `className` did not match.
Read more >
Class name hydration mismatch in server and client, (Warning
Class name hydration mismatch in server and client, (Warning: Prop `className` did not match Server and Client) ; import React ; import {create} ......
Read more >
Prop `className` did not match. Server.... react js next js ...
Coding example for the question Prop `className` did not match. ... Class name hydration mismatch in server and client, (Warning: Prop `className` did...
Read more >
react-hydration-error - Next.js
When css-in-js libraries are not set up for pre-rendering (SSR/SSG) it will often lead to a hydration mismatch. In general this means the...
Read more >
Handling the React server hydration mismatch error
For prop errors, the warning looks something like: Warning: Prop `className` did not match. Server: "positive" Client: "zero".
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found