Next.js+MaterialUI出现className不匹配报错、首屏MUI样式失效问题
问题根因
该className不匹配报错本质是服务端渲染阶段生成的MUI类名序号,和客户端hydration阶段生成的类名序号不一致导致的,首屏样式丢失也是因为类名不匹配导致样式无法正常命中。你的基础SSR样式收集配置是正确的,缺少以下关键配置:
解决步骤
1. 统一服务端和客户端的类名生成逻辑
新增src/utils/createGenerateClassName.ts文件,统一JSS类名生成规则,避免两端生成逻辑差异:
import { createGenerateClassName } from '@material-ui/core/styles'; const generateClassName = createGenerateClassName({ productionPrefix: 'mui', disableGlobal: true }); export default generateClassName;
2. 修改_document.tsx配置
在初始化ServerStyleSheets时传入统一的类名生成器:
// 新增导入 import generateClassName from '../src/utils/createGenerateClassName'; // 找到getInitialProps里的初始化逻辑,修改为: const sheets = new ServerStyleSheets({ generateClassName });
其余代码保持不变即可。
3. 修改_app.tsx配置
新增StylesProvider包裹根组件,传入同一个类名生成器,确保客户端类名生成逻辑和服务端一致:
// 新增导入 import { StylesProvider } from '@material-ui/core'; import generateClassName from '../src/utils/createGenerateClassName'; // 修改返回的组件结构: return ( <React.Fragment> <Head> <title>My App</title> <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" /> </Head> <StylesProvider generateClassName={generateClassName}> <ThemeProvider theme={theme}> <CssBaseline /> <Component {...pageProps} /> </ThemeProvider> </StylesProvider> </React.Fragment> );
4. 兼容NextJS 11编译逻辑
NextJS 11默认开启的SWC编译会和MUI4的JSS逻辑产生冲突,新增.babelrc文件切换为babel编译:
{ "presets": ["next/babel"], "plugins": [ [ "babel-plugin-import", { "libraryName": "@material-ui/core", "libraryDirectory": "esm", "camel2DashComponentName": false } ] ] }
安装对应依赖:
npm install babel-plugin-import --save-dev
额外排查项
- 不要在组件外部的顶层作用域直接执行
makeStyles返回的样式函数,所有makeStyles生成的hook必须在组件内部调用 - 确保服务端和客户端生成的theme完全一致,不要添加仅在客户端存在的theme属性
- 不要在组件渲染逻辑中添加仅在客户端触发的条件渲染,避免SSR和客户端渲染结构不一致
内容的提问来源于stack exchange,提问作者zilijonas
相关产品推荐
相关产品推荐

