Reputation: 439
I'm creating a NextJS app that uses React Material-Ui and I'm getting the Prop 'className' did not match.
error, even though I changed my _app.tsx
and _document.tsx
according to the documentation.
My _app.tsx
:
// pages/_app.tsx
/* eslint-disable react/jsx-props-no-spreading */
import { FC, useEffect } from 'react';
import CssBaseline from '@material-ui/core/CssBaseline';
import { ThemeProvider } from '@material-ui/core/styles';
import { AppProps } from 'next/app';
import Head from 'next/head';
import { defaultTheme as theme } from '../src/themes';
const MyApp: FC<AppProps> = ({ Component, pageProps }) => {
useEffect(() => {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles) {
jssStyles?.parentElement?.removeChild(jssStyles);
}
}, []);
return (
<>
<Head>
<title>My App</title>
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width"
/>
</Head>
<ThemeProvider theme={theme}>
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
<CssBaseline />
<Component {...pageProps} />
</ThemeProvider>
</>
);
};
export default MyApp;
My _document.tsx
:
import React from 'react';
import Document, {
Html,
Head,
Main,
NextScript,
DocumentProps,
DocumentContext,
} from 'next/document';
import { ServerStyleSheets } from '@material-ui/core/styles';
import { defaultTheme as theme } from '../src/themes';
export default class MyDocument extends Document {
static getInitialProps = async (ctx: DocumentContext) => {
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(),
],
};
};
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,800,900&display=swap"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
Browser Console Error:
Warning: Prop `className` did not match. Server: "MuiBox-root MuiBox-root-10" Client: "MuiBox-root MuiBox-root-13"
div
StyledComponent@webpack-internal:///./node_modules/@material-ui/styles/esm/styled/styled.js:95:22
div
Grid@webpack-internal:///./node_modules/@material-ui/core/esm/Grid/Grid.js:236:29
WithStyles@webpack-internal:///./node_modules/@material-ui/styles/esm/withStyles/withStyles.js:61:25
div
Grid@webpack-internal:///./node_modules/@material-ui/core/esm/Grid/Grid.js:236:29
WithStyles@webpack-internal:///./node_modules/@material-ui/styles/esm/withStyles/withStyles.js:61:25
div
Container@webpack-internal:///./node_modules/@material-ui/core/esm/Container/Container.js:85:17
WithStyles@webpack-internal:///./node_modules/@material-ui/styles/esm/withStyles/withStyles.js:61:25
div
StyledComponent@webpack-internal:///./node_modules/@material-ui/styles/esm/styled/styled.js:95:22
div
StyledComponent@webpack-internal:///./node_modules/@material-ui/styles/esm/styled/styled.js:95:22
Home@webpack-internal:///./pages/index.tsx:93:17
ThemeProvider@webpack-internal:///./node_modules/@material-ui/styles/esm/ThemeProvider/ThemeProvider.js:42:18
MyApp@webpack-internal:///./pages/_app.tsx:37:19
ErrorBoundary@webpack-internal:///./node_modules/@next/react-dev-overlay/lib/internal/ErrorBoundary.js:26:47
ReactDevOverlay@webpack-internal:///./node_modules/@next/react-dev-overlay/lib/internal/ReactDevOverlay.js:86:20
Container@webpack-internal:///./node_modules/next/dist/client/index.js:254:20
AppContainer@webpack-internal:///./node_modules/next/dist/client/index.js:750:18
Root@webpack-internal:///./node_modules/next/dist/client/index.js:889:19
I just can't figure out what's happening. Any suggestion?
Upvotes: 9
Views: 8823
Reputation: 1538
Next.js supports lazy loading React components with next/dynamic. In the main Layout component you can add this wrapper and export it.
In Layout.jsx
import dynamic from 'next/dynamic'
now wrap your export component with dynamic as below
export default dynamic(() => Promise.resolve(Layout), { ssr: false })
now this component can delay hydration until the Suspense boundary is resolved.
Upvotes: 2
Reputation: 41
Only this worked for me https://github.com/vercel/next.js/issues/7322#issuecomment-987086391
import React from "react";
const ClientOnly = ({ children, ...delegated }) => {
const [hasMounted, setHasMounted] = React.useState(false);
React.useEffect(() => {
setHasMounted(true);
}, []);
if (!hasMounted) return null
return (
<React.Fragment {...delegated}>
{children}
</React.Fragment>
);
}
export default ClientOnly
wrap the form ->
<ClientOnly>
<SomeComponnet/>
</ClientOnly>
Upvotes: 4
Reputation: 439
Setting 'reactStrictMode' to false inside next.config.js seems to solve the issue
/** @type {import('next').NextConfig} */
module.exports = {
reactStrictMode: false,
}
I don't really know why that's the case. If anyone knows, feel free to explain in the comments
Upvotes: 5