Next.js集成Material-ui样式失效,报className不匹配警告求助
解决Next.js + Material-UI 服务端/客户端 className 不匹配及样式失效问题
我之前也碰到过几乎一模一样的问题,结合你的代码和描述,核心问题可以拆成几个点来修复:
1. 自定义 Server 里的致命错误:dev 变量判断完全写反
你的 server.js 里这一行逻辑搞反了:
const dev = process.env.NODE_ENV === "production";
这意味着当你线上设置 NODE_ENV=production 时,Next.js 反而会以开发模式启动。而开发模式下 Material-UI 的 JSS 会生成动态类名,和生产模式的静态哈希类名完全不匹配,直接导致 className did not match 警告和样式失效。
修正后的 server.js 应该是:
const express = require("express"); const next = require("next"); const port = parseInt(process.env.PORT, 10) || 3000; // 正确逻辑:只有开发环境下 dev 才为 true const dev = process.env.NODE_ENV !== "production"; const app = next({ dev }); const handle = app.getRequestHandler(); app.prepare().then(() => { const server = express(); server.get("*", (req, res) => { return handle(req, res); }); server.listen(port, err => { if (err) throw err; console.log(`> Ready on http://localhost:${port}`); }); });
2. 修复依赖版本不匹配问题
你提到使用的是 Material-UI 3.9.3,但 package.json 里 @material-ui/core 用的是 "next"(会自动安装 beta 版),这会和 Next.js 8.0.4 产生版本冲突。需要统一指定稳定兼容的版本:
更新后的 package.json 依赖部分:
{ "dependencies": { "@material-ui/core": "3.9.3", "@material-ui/icons": "^3.0.2", "@material-ui/styles": "3.0.0-alpha.10", // 和 3.9.3 匹配的样式包版本 "apollo-boost": "^0.3.1", "clsx": "^1.0.4", "express": "^4.16.4", "graphql": "^14.2.0", "isomorphic-unfetch": "^3.0.0", "joi-browser": "^13.4.0", "jss": "^10.0.0", // 兼容 Material-UI 3.x 的 JSS 版本 "next": "8.0.4", "prop-types": "^15.7.2", "react": "^16.8.6", // 和 Next.js 8.0.4 匹配的 React 版本 "react-apollo": "^2.5.3", "react-dom": "^16.8.6" } }
执行 npm install 重新安装依赖,确保版本统一。
3. 配置 _app.js 处理服务端样式收集
为了让服务端渲染的样式能正确传递到客户端,需要在 pages/_app.js 中使用 Material-UI 的 ServerStyleSheets 来收集服务端样式:
创建或修改 pages/_app.js:
import React from 'react'; import App, { Container } from 'next/app'; import { ThemeProvider } from '@material-ui/core/styles'; import createMuiTheme from '@material-ui/core/styles/createMuiTheme'; import { ServerStyleSheets } from '@material-ui/styles'; // 自定义主题(可根据你的需求调整) const theme = createMuiTheme({ palette: { primary: { main: '#1976d2', }, }, }); class MyApp extends App { static async getInitialProps({ Component, ctx }) { const sheets = new ServerStyleSheets(); const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {}; // 拦截页面渲染,收集服务端样式 const originalRenderPage = ctx.renderPage; ctx.renderPage = () => originalRenderPage({ enhanceApp: (App) => (props) => sheets.collect(<App {...props} />), }); return { pageProps, // 将收集到的样式传递给客户端 styles: sheets.getStyleElement(), }; } render() { const { Component, pageProps, styles } = this.props; return ( <Container> {/* 注入服务端渲染的样式,避免客户端重绘时样式丢失 */} {styles} <ThemeProvider theme={theme}> <Component {...pageProps} /> </ThemeProvider> </Container> ); } } export default MyApp;
4. 线上部署验证步骤
- 先在本地测试生产模式:
访问页面确认警告消失,样式正常加载。npm run build npm run prod_start - 线上服务器执行相同流程:
- 拉取最新代码
- 执行
npm install - 执行
npm run build - 用 PM2 启动服务时,确保
NODE_ENV=production环境变量已正确设置(可以在 PM2 配置文件里指定)
做完这些步骤后,应该就能彻底解决 className did not match 的警告和样式失效问题了。
内容的提问来源于stack exchange,提问作者Rigal
相关产品推荐
相关产品推荐

