You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js集成Material UI 4页面刷新后样式丢失问题排查

Next.js + Material UI 4 首屏样式丢失、类名不匹配问题修复

问题原因

该问题本质是SSR阶段生成的MUI类名哈希与客户端水合阶段生成的类名不一致:服务端输出的带类名的DOM和样式,在客户端启动后因为类名对不上被判定为无效,导致首屏无样式,直到热更新触发客户端重新渲染才会生成正确样式,控制台抛出的Prop className did not match就是类名不一致的直接提示。
你当前的配置有两个核心遗漏:

  • 没有统一服务端、客户端的JSS类名生成规则,两边计算出的类名哈希不同
  • 没有固定JSS样式的注入锚点,服务端和客户端插入样式的位置不一致,导致样式优先级、类名匹配都出问题

修复方案

按以下步骤调整配置即可:

  • 修正_document.js配置,预留JSS注入锚点,确保服务端完整收集全组件树的MUI样式
import React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { ServerStyleSheets } from '@material-ui/core/styles';
import theme from "@helper/theme/theme";

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
        <Head>
          <meta name="theme-color" content={theme.palette.primary.main} />
          {/* 固定JSS服务端样式注入锚点 */}
          <style id="jss-server-side" />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

MyDocument.getInitialProps = async (ctx) => {
  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: [
      ...React.Children.toArray(initialProps.styles),
      sheets.getStyleElement()
    ],
  };
};
  • 修正_app.js配置,引入StylesProvider统一客户端、服务端的类名生成规则
import '@assets/fonts/global.css';
import React from 'react';
import Layout from "@layout/Layout";
import Footer from "@layout/Footer/Footer";
import Header from "@layout/Header/Header";

// Material UI
import CssBaseline from "@material-ui/core/CssBaseline";
import theme from "@helper/theme/theme";
import { 
  ThemeProvider as MuiThemeProvider, 
  createGenerateClassName, 
  StylesProvider 
} from "@material-ui/styles";

// Redux
import { wrapper } from "@store/store";

// 固定类名生成规则,保证服务端/客户端生成的类名哈希完全一致
const generateClassName = createGenerateClassName({
  productionPrefix: 'jss',
  seed: 'mui-app'
});

function MyApp({ Component, pageProps }) {
  React.useEffect(() => {
    // 水合完成后移除服务端注入的冗余CSS
    const jssStyles = document.querySelector('#jss-server-side');
    if (jssStyles?.parentElement) {
      jssStyles.parentElement.removeChild(jssStyles);
    }
  }, []);

  return (
    <StylesProvider generateClassName={generateClassName}>
      <MuiThemeProvider theme={theme}>
        <CssBaseline />
        <Header />
        <Layout>
          <Component {...pageProps} />
        </Layout>
        <Footer />
      </MuiThemeProvider>
    </StylesProvider>
  );
}

export default wrapper.withRedux(MyApp);
  • 检查主题配置:确保@helper/theme/theme导出的是静态主题对象,不要在组件渲染函数内动态创建主题实例,否则每次渲染都会生成新的类名规则。
  • 删除项目根目录下的.next缓存文件夹,重启开发服务即可生效。

内容的提问来源于stack exchange,提问作者fahad shaikh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 23:54:33