vercel / next.js

The React Framework
https://nextjs.org
MIT License
122.3k stars 26.18k forks source link

Warning: Prop className did not match. #7322

Closed th0th closed 4 years ago

th0th commented 5 years ago

Examples bug report

Example name

with-styled-components

Describe the bug

Also posted here: #2538

Using css prop introduced with styled-components v4 causes Warning: Prop className did not match..

To Reproduce

Add any HTML element with css prop.

Expected behavior

Correctly styled rendering on the server side without any warnings.

Screenshots

57497472-7b657c00-72e0-11e9-84c5-e7e5fa0d351c

System information

Additional context

Here is an example I created to demonstrate the issue: https://codesandbox.io/embed/jlwvwyy0ow

Open this and refresh once the building is done: https://jlwvwyy0ow.sse.codesandbox.io/

ziimakc commented 4 years ago

anyone gets this error again?

ziimakc commented 4 years ago

in my case problem was with reexporting styled components after aplaying typescript Theme type:

import { Theme } from '@shared'
import * as styledComponents from 'styled-components'
import { ThemedStyledComponentsModule } from 'styled-components'

const {
  default: styled,
  css,
  keyframes,
  ThemeProvider,
  createGlobalStyle,
  ServerStyleSheet
} = (styledComponents as unknown) as ThemedStyledComponentsModule<Theme>

export { css, keyframes, styled, ThemeProvider, createGlobalStyle, ServerStyleSheet }

After i rewrite import to standart styled-components error has gone.

jaedung commented 4 years ago

For those who are using material-ui, the following code should be added in _document.tsx .

import React from 'react';
import Document, { Head, Main, NextScript } from 'next/document';
import { ServerStyleSheets } from '@material-ui/core/styles';
import theme from '../src/theme';

export default class MyDocument extends Document {
  render() {
    return (
      <html lang="en">
        <Head>
          {/* PWA primary color */}
          <meta name="theme-color" content={theme.palette.primary.main} />
          <link
            rel="stylesheet"
            href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </html>
    );
  }
}

MyDocument.getInitialProps = async ctx => {
  // Resolution order
  //
  // On the server:
  // 1. app.getInitialProps
  // 2. page.getInitialProps
  // 3. document.getInitialProps
  // 4. app.render
  // 5. page.render
  // 6. document.render
  //
  // On the server with error:
  // 1. document.getInitialProps
  // 2. app.render
  // 3. page.render
  // 4. document.render
  //
  // On the client
  // 1. app.getInitialProps
  // 2. page.getInitialProps
  // 3. app.render
  // 4. page.render

  // Render app and page and get the context of the page with collected side effects.
  const sheets = new ServerStyleSheets();
  const originalRenderPage = ctx.renderPage;

  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: App => props => sheets.collect(<App {...props} />),
    });

  const initialProps = await Document.getInitialProps(ctx);

  return {
    ...initialProps,
    // Styles fragment is rendered after the app and page rendering finish.
    styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()],
  };
};

The code is from https://github.com/mui-org/material-ui/blob/master/examples/nextjs/pages/_document.js

dheerajmpai commented 4 years ago

This is a bug. Check out here https://github.com/mui-org/material-ui/issues/18018

adriangzz commented 4 years ago

I'm not using any ui framework and i'm getting this error.

edgarcheverier commented 4 years ago

Following this article, I managed to make it work but isn't straight forward, I hope it can help someone. https://medium.com/manato/ssr-with-next-js-styled-components-and-material-ui-b1e88ac11dfa

carlos-menezes commented 4 years ago

I'm having this issue aswell. The background image of the Logo components disappears after I reload the page, having made changes to the code. I'm using antd components.

import styled from 'styled-components'

interface NavigationProps {
  selected: string;
}

const Navigation = (props: NavigationProps) => {
  return (
    <Header>
      <Logo />
      <Menu
        theme="dark"
        mode="horizontal"
        defaultSelectedKeys={[props.selected]}
        style={{ lineHeight: '64px' }}
      >
        <Menu.Item key="Index">nav 1</Menu.Item>
        <Menu.Item key="About">nav 2</Menu.Item>
      </Menu>
    </Header>
  )
}

const Logo = styled.div`
  width: 120px;
  height: auto;
  background-image: url('images/logo.svg');
  background-size: contain;
  background-position: left center;
  background-repeat: no-repeat;
  margin: 16px 24px 16px 0;
  float: left;
`
TheDSCPL commented 4 years ago

@carlos-menezes Have you read these links? https://styled-components.com/docs/advanced#server-side-rendering https://styled-components.com/docs/tooling#babel-plugin

nicholasmordecai commented 4 years ago

So I managed to fix this in my situation.. I'm just running React 16.12.0, Next 9.2.1 and Material 4.9.1. Much like everyone else here I found that it was fine on the initial save, however when reloading in browser it was throwing an error where the class names were different. I found a fix for now.

$ npm install --save-dev babel-plugin-styled-components
$ touch .babelrc

Paste the following into your .babelrc file -

{
    "plugins": [
      ["styled-components", { "ssr": true, "displayName": true, "preprocess": false } ],
    ],
    "presets": ["next/babel"]
}

Just re-run your dev env and the problem went away. Apologies if I've done something stupid here, I'm still relatively new to next.js & react!

jordykoppen commented 4 years ago

Okay, so I've been plagued by this issue for a couple of weeks now. Only just realized that only .babelrc is picked up by Next. I recently switched to vim and appended the filename with .json for vim to recognize it as a JSON file

In short: Make sure you're using .babelrc instead of .babelrc.json

TimothyDalbey commented 4 years ago

I've followed the advice here about adding a .babelrc etc but the issue still occurs every time I refresh the page.

jordykoppen commented 4 years ago

@TimothyDalbey Do you have a repo that reproduces your problem?

TimothyDalbey commented 4 years ago

@jordykoppen Pretty new with Next.js - but FWIW:

.babelrc:

{
  "presets": ["next/babel"],
  "plugins": [
    [
      "styled-components",
      { "ssr": true, "displayName": true, "preprocess": false }
    ]
  ]
}

pages/index.js:

import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles';
import { makeStyles } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import { Box } from '@material-ui/core'
import Typography from '@material-ui/core/Typography';

const theme = createMuiTheme({
  typography: {
    fontSize: 12,
    h1: {
      textTransform: 'uppercase',
      fontWeight: 'bold',
      textOverflow: "clip",
      letterSpacing: "1em",
      textShadow: "-8px 0 2px rgba(30,242,241, 0.8) , 8px 0 2px rgba(246,5,10, 0.8)"
    }
  },
});

const useStyles = makeStyles(theme => ({
  root: {
    flexGrow: 1,
  },
  control: {
    padding: theme.spacing(2),
  }
}));

export default function Index() {
  const classes = useStyles();
  return (
    <ThemeProvider theme={theme}>
      <Grid container className={classes.root} spacing={2}>
        <Grid item xs={12}>
          <Grid
            container
            spacing={0}
            direction="column"
            alignItems="center"
            justify="center"
            style={{ minHeight: '100vh' }} spacing={2}
          >
            <Grid item style={{ margin: 'auto'}}>
              <Box alignItems="center">
                <Typography variant="h1" component="h1">Howdy</Typography>
              </Box>
            </Grid>
          </Grid>
        </Grid>
      </Grid>
    </ThemeProvider>
  );
}
jordykoppen commented 4 years ago

@TimothyDalbey what about _document.js

TimothyDalbey commented 4 years ago

@TimothyDalbey what about _document.js

I don't have one. Is that the issue?

jordykoppen commented 4 years ago

@TimothyDalbey That's the issue πŸ˜„ Have a look HERE for reference

nooblyf commented 4 years ago

@megmut Thanks it worked I was pulling my hair off.

5ervant commented 4 years ago

So I managed to fix this in my situation.. I'm just running React 16.12.0, Next 9.2.1 and Material 4.9.1. Much like everyone else here I found that it was fine on the initial save, however when reloading in browser it was throwing an error where the class names were different. I found a fix for now.

$ npm install --save-dev babel-plugin-styled-components
$ touch .babelrc

Paste the following into your .babelrc file -

{
    "plugins": [
      ["styled-components", { "ssr": true, "displayName": true, "preprocess": false } ],
    ],
    "presets": ["next/babel"]
}

Just re-run your dev env and the problem went away. Apologies if I've done something stupid here, I'm still relatively new to next.js & react!

But installing babel-plugin-styled-components on a next-expo app with @expo/next-adapter takes forever.

Hubro commented 4 years ago

This is driving me INSANE.

Any time I reload my window, or the content of my screen is temporarily replaced with (i.e.) an error message, all my styles go out the window and my app looks like garbage, and I have to restart the development server.

The error message in the console is always some variation of this:

index.js:1 Warning: Prop className did not match. Server: "MuiPaper-root MuiDrawer-paper makeStyles-drawerPaper-75 makeStyles-drawerPaper-291 MuiDrawer-paperAnchorLeft MuiDrawer-paperAnchorDockedLeft MuiPaper-elevation0" Client: "MuiPaper-root MuiDrawer-paper makeStyles-drawerPaper-75 makeStyles-drawerPaper-76 MuiDrawer-paperAnchorLeft MuiDrawer-paperAnchorDockedLeft MuiPaper-elevation0"

I'm using Next.js with Relay and MUI.

Here are all my dependencies if it helps:

  "devDependencies": {
    "@babel/core": "^7.8.6",
    "@storybook/addon-actions": "^5.3.14",
    "@storybook/addon-links": "^5.3.14",
    "@storybook/addons": "^5.3.14",
    "@storybook/react": "^5.3.14",
    "@types/markdown-to-jsx": "^6.11.0",
    "@types/node": "^13.7.7",
    "@types/react": "^16.9.23",
    "@types/react-datepicker": "^2.11.0",
    "@types/react-relay": "^7.0.3",
    "@types/relay-runtime": "^8.0.7",
    "babel-loader": "^8.0.6",
    "babel-plugin-react-require": "^3.1.3",
    "babel-plugin-relay": "^9.0.0",
    "babel-preset-react-app": "^9.1.1",
    "get-graphql-schema": "^2.1.2",
    "graphql": "^14.6.0",
    "relay-compiler": "^9.0.0",
    "relay-compiler-language-typescript": "^12.0.0",
    "relay-config": "^9.0.0",
    "typescript": "^3.8.3"
  },
  "dependencies": {
    "@date-io/date-fns": "^1",
    "@material-ui/core": "^4.9.1",
    "@material-ui/icons": "^4.9.1",
    "@material-ui/pickers": "^3.2.10",
    "isomorphic-unfetch": "^3.0.0",
    "markdown-to-jsx": "^6.11.0",
    "next": "^9.2.1",
    "react": "^16.12.0",
    "react-datepicker": "^2.13.0",
    "react-dom": "^16.12.0",
    "react-relay": "^9.0.0",
    "relay-runtime": "^9.0.0"
  }

As well as my next.config.js:

const path = require("path");

module.exports = {
  pageExtensions: ["tsx"],

  webpack: config => {
    config.resolve.alias['~'] = path.resolve(__dirname) + "/src";
    return config;
  },
};

And my .babelrc:

{
    "presets": [
        "next/babel"
    ],
    "plugins": [
        "relay"
    ]
}
jordykoppen commented 4 years ago

@Hubro you need to install babel-plugin-styled-components and add it to your .babelrc.json. Also, don’t forget to add the .json extension to the babelrc as it otherwise won’t load.

Hubro commented 4 years ago

@jordykoppen This doesn't work for me. I have added the plugin just as described by @5ervant and restarted my dev server, and it has no effect:

.babelrc:

{
    "presets": [
        "next/babel"
    ],
    "plugins": [
        "relay",
        [
          "styled-components",
          {
            "ssr": true,
            "displayName": true,
            "preprocess": false
          }
        ]
    ]
}

I don't understand what you mean by having to rename .babelrc to .babelrc.json. The Next.js docs don't mention a .json extension, and obviously my .babelrc is already working since I'm using it to include Relay. In fact, if I add the .json Next.js no longer detects it and my setup breaks.

5ervant commented 4 years ago

@Hubro Is your Material-UI's styling layout on your "./pages/_app.js"? It becomes better when I wrap all my "./pages/*.js" with my Material-UI's styling layout. Sometimes the styles are there, something they're not.

Whenever I tried to use my wrapper on my "./pages/_document.js", I'm getting Internal Server Error. Let me know if you succeed using a wrapper on "./pages/_document.js".

My suspecting reason for this is because Material-UI's styling is being rendered on the client dynamically and the "./pages/_app.js" was specifically build for server-side rendering (SSR).

Hubro commented 4 years ago

@5ervant What do you mean by styling layout?

I did have my ThemeProvider and MuiPickersUtilsProvider in my _app.js page. I concur that Material UI has something to do with this, because I never had this issue in my application before I added it.

I have now removed everything Material UI related from _app.js so it looks plain like this:

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
    </>
  );
}

export default MyApp;

I am now adding my theme and utils directly on my page component. I also have the styled-components plugin active as you recommended.

None of this has made any difference, and my styles all still break when I reload the window.

valmassoi commented 4 years ago

this is what fixed it for me https://github.com/mui-org/material-ui/blob/master/examples/nextjs/pages/_document.js#L27

jeanbispo commented 4 years ago

So I managed to fix this in my situation.. I'm just running React 16.12.0, Next 9.2.1 and Material 4.9.1. Much like everyone else here I found that it was fine on the initial save, however when reloading in browser it was throwing an error where the class names were different. I found a fix for now.

$ npm install --save-dev babel-plugin-styled-components
$ touch .babelrc

Paste the following into your .babelrc file -

{
    "plugins": [
      ["styled-components", { "ssr": true, "displayName": true, "preprocess": false } ],
    ],
    "presets": ["next/babel"]
}

Just re-run your dev env and the problem went away. Apologies if I've done something stupid here, I'm still relatively new to next.js & react!

Thanks man, it works for me.

mrusmanali commented 4 years ago

guys, I think it's because you have _document file in your pages folder and material-ui needs this

import { ServerStyleSheets } from '@material-ui/core/styles';

just follow @valmassoi guideline.

Shaker-Hamdi commented 4 years ago

@valmassoi Do you know what should I do if I don't use Material UI and I'm still having this issue?

valmassoi commented 4 years ago

@valmassoi Do you know what should I do if I don't use Material UI and I'm still having this issue?

not sure sorry

adonig commented 4 years ago

I was able to solve my case of this problem after two hours of searching by removing a conditional render:

const isSSR = typeof window === "undefined";

{!isSSR && <GdprDialog />}

<Footer /> {/* The error happens inside this component. */}

It seems like Material UI's makeStyles function increments a number it appends to the class names to keep them unique. So during server-side rendering the class name used in the Footer component differs from the class name used during client-side rendering because makeStyles increments the number when rendering the GdprDialog component.

joaocjesus commented 4 years ago

@valmassoi answer fixed it for me. I didn't have a _document.js, so I just added the one he linked (with some small tweaks) and that fixed the issue for me. No longer shows the console error. πŸ‘

github0013 commented 4 years ago

My situation was something like this.

  1. It is a dynamic component
  2. When user is NOT logged in, display gray color avatar
  3. when user is logged in, display avatar in a color
  4. I control the color by adding a className "logged-in"

https://github.com/zeit/next.js/issues/7322#issuecomment-612965316 Maybe for this reason, the displayed avatar was in gray color even the user was logged in on a page refresh/reload. (while editing in dev mode, hot reload kinda picks up and was showing colored avatar, but it was still buggy)

I then did something like this


  const [loggedIn, setLoggedIn] = React.useState(false)
  React.useEffect(() => {
    setLoggedIn(check_if_user_is_signed_in())
  }, [check_if_user_is_signed_in()])

  if (loggedIn) {
    return (
      <Link href="/users">
        <IconButton>
          <Avatar className="user logged-in" />
        </IconButton>
      </Link>
    )
  }

  return (
    <Link href="/login">
      <IconButton>
        <Avatar className="user" />
      </IconButton>
    </Link>
  )

and it seems to work fine.

cdaz5 commented 4 years ago

@Shaker-Hamdi i'm not using material UI and still had the issue .. following this advice earlier in the thread fixed it for me .. hope it helps! https://github.com/zeit/next.js/issues/7322#issuecomment-592593330

github0013 commented 4 years ago

https://nextjs.org/docs/advanced-features/dynamic-import was another way to avoid this warning.

https://github.com/zeit/next.js/discussions/12338#discussioncomment-8285

gauravkrp commented 4 years ago

I am having the similar issue when using https://react-slick.neostack.com/ slider component in my nextjs project. Please reopen this issue.

gauravkrp commented 4 years ago

https://nextjs.org/docs/advanced-features/dynamic-import was another way to avoid this warning.

#12338 (comment)

Yes, I just discovered this method and it works in my case as my components has data to load on client side. option SSR needs to be false so that component is loaded on the client side dynamically and is not SSR. In my case, the slider components has classes that are initialized and added to elements on client side after the document window is ready. So, the solution will work in all similar cases where the classes are initialized and added on the client side. See my code below.

const AGSlider = dynamic( () => import('../components/slider'), { ssr: false, loading: () => <Loader /> } )

ardaerzin commented 4 years ago

I too am having this issue in my workspace. before anything else I should mention that I have the custom _document.js (even tried the new experimental plugin approach without the custom document), and the .babelrc ready.

everything works just fine in a single project, but I want to switch to yarn workspaces because I am managing a few projects which share a common set of UI components. under the workspace, I keep getting this error. interestingly if I publish those packages as a private repo and use them that way, I don't get this error. yes I also am using next-transpile-modules

I am not using material-ui, but I use grommet & styled-components. Grommet components I use in my modules don't trigger this error, but when I use styled(Component) I start seeing errors.

idk it's been really bugging me since yesterday. any help or suggestion is appreciated

github0013 commented 4 years ago

@ardaerzin

https://github.com/zeit/next.js/discussions/12338#discussioncomment-8285 check this one out.

I think this problem is more like because of SSR feature in nextjs rather than any kinds of external libraries. Described in the bare-minimum example I have in the above link, it still shows the same warning. (check the package.json, and also I am not using _app or _document)

One solution for this is that you use

https://nextjs.org/docs/advanced-features/dynamic-import

on the component which dynamically changes contents depending on the client.

ardaerzin commented 4 years ago

@github0013 thanks! will take a look.

the weird part is that when I start dev server with now dev it runs without any errors on the first load. as soon as I update one component and trigger a refresh, the error comes back.

so far my workspace structure looks like this:

workspace
β”‚
└─── ui
β”‚   β”‚   Button
β”‚   β”‚   Footer
β”‚   β”‚   Header
β”‚   
└───project
β”‚   └───pages
β”‚       β”‚   _app.js

I am using an _app.js to manage my shared layout. there I am using header & footer. another fun thing is, both of those components are using other components from the UI module. the header alone is not causing any problems, but the same button component in my footer is causing this issue. footer has no dynamically changing content which may be different on the client.

ok, I know this is not a breaking issue because if I npm publish my modules everything is normal. but for a better dev environment, it'd be super cool to somehow tackle this. I may avoid the error using dynamic imports but I don't know if it is the best solution every time I run into this exact problem.

github0013 commented 4 years ago

@ardaerzin

What does the warning / error say exactly? And it's maybe wise to create a bare-minimum project and test the components.

mkdir bare-min
cd bare-min
yarn add next react react-dom
mkdir pages
touch pages/index.js
code pages/index.js
yarn dev
ardaerzin commented 4 years ago

@github0013 should've said warning my bad, spending a day after this got me tired. it says

index.js:1 Warning: Prop `className` did not match. Server: "StyledButton-sc-323bzc-0 fbhfmY sc-fzozJi hXjicF" Client: "StyledButton-sc-323bzc-0 fbhfmY sc-AxirZ iGicTr"

so I know it is coming from the button component in my UI package. the first 2 classes which are identical are coming from grommet. the last two are added when I use styled-components to add my style rules.

since this is only happening inside a yarn workspace, I created a bare minimum workspace in which this issue reproduced. just used the one in nextjs examples folder and added very basic components to test. https://github.com/ardaerzin/mono-test/commit/f994f4bdfecf7dc945c1ba70a0c849d97e8f539d

the situation is the same here, no warnings when I run yarn dev the first time, but the warning appears after a refresh and stays there for good.

diegomjasso commented 4 years ago

The solution is here: https://stackoverflow.com/a/61621949/7741752

ardaerzin commented 4 years ago

@diegomjasso thanks a lot for the suggestion. however, I just tried your approach but it is not working on that test repo I shared above :/

github0013 commented 4 years ago

@ardaerzin

https://github.com/github0013/nextjs-grommet/tree/master

I tried grommet on my own. (never used grommet before). I see no more warnings after this setup. As far as I checked ...

  1. yes, I saw Warning: Prop className did not match, before adding .babelrc + _document.tsx
  2. once the button got styled text label (red color), it seemed browser was caching it hard? I experienced the browser didn't show the warning even after
    • hard refresh
    • rm -fr .next
    • moving _document out of pages
    • moving .babelrc out of the directory
    • rebooting docker
  3. sometimes the styled text label was in black color (although it meant to be in red), and I saw no warnings.

There were some inconsistencies like that, but I am pretty much sure in your case, it's coming from styled-components.

adventurini commented 4 years ago

I am having the similar issue when using https://react-slick.neostack.com/ slider component in my nextjs project. Please reopen this issue.

Having the issue with Chakra.

arbaouimehdi commented 4 years ago

I am having the similar issue when using https://react-slick.neostack.com/ slider component in my nextjs project. Please reopen this issue.

Having the issue with Chakra.

This what I follow to solve this problem:

https://github.com/zeit/next.js/issues/7423#issuecomment-592594730

FBosler commented 4 years ago

There are multiple solutions being referenced throughout the thread, is there a "best-practice" solution, or a reliable SO thread that explains what's going on here?

simjoeweb commented 4 years ago

I am having the similar issue when using https://react-slick.neostack.com/ slider component in my nextjs project. Please reopen this issue.

Having the issue with Chakra.

Did you find a solution?

gauravkrp commented 4 years ago

I am having the similar issue when using https://react-slick.neostack.com/ slider component in my nextjs project. Please reopen this issue.

Having the issue with Chakra.

Here is one viable solution - https://github.com/zeit/next.js/issues/7322#issuecomment-623491977

brianpunzalan commented 4 years ago

I have upraded my next.js version to 9 and got this problem. However, I have fixed it by using useStyles instead of withStyles on my component that having this issue. I have been encountering this problem on Material UI.

bengrunfeld commented 4 years ago

FYI - also encountering this problem with Prism.js