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

Next.js+MUI SSR场景下Switch异常及className不匹配问题

问题根因

你遇到的报错和组件渲染异常属于同源问题,核心原因是服务端渲染与客户端渲染的执行环境不一致:

  • js-cookie只能在浏览器客户端环境运行,服务端渲染阶段无法读取浏览器存储的Cookie,原有逻辑在Store初始化时直接调用Cookies.get(),服务端执行时永远拿到空值,默认渲染浅色主题、Switch关闭状态的DOM
  • 客户端注水阶段才会真正读取到Cookie里存储的深色模式配置,触发二次渲染输出深色主题、Switch开启的DOM,前后端输出的DOM结构、元素className完全不一致,就会抛出Prop className did not match Server and Client报错,同时出现Switch首屏显示关闭、二次渲染后才恢复正常的异常
  • 原有_document.js仅处理了MUI基础样式的服务端收集,没有处理主题状态在服务端/客户端的同步逻辑,所以参考的通用集成方案没有生效。

修复步骤

1. 调整全局状态初始化逻辑,避免SSR阶段直接读取客户端Cookie

修改Store.js,将darkMode初始值统一设为默认值,不在服务端执行阶段读取Cookie:

import Cookies from "js-cookie";
import { createContext, useReducer } from "react";

export const Store = createContext();

// SSR阶段统一使用默认浅色主题,不读取客户端存储
const initialState = {
  darkMode: false,
};

const reducer = (state, action) => {
  switch (action.type) {
    case "DARK_MODE_ON":
      return { ...state, darkMode: true };
    case "DARK_MODE_OFF":
      return { ...state, darkMode: false };
    default:
      return state;
  }
};

export const StoreProvider = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, initialState);
  const value = { state, dispatch };
  return <Store.Provider value={value}>{children}</Store.Provider>;
};

2. 修改_app.js,在客户端注水完成后同步Cookie中的主题配置

通过useEffect钩子在客户端首屏渲染完成后读取Cookie同步主题状态,同时保留原有清理服务端注入JSS样式的逻辑,保证前后端首屏输出的DOM完全一致:

import { useEffect, useContext } from "react";
import "../styles/globals.css";
import { StoreProvider, Store } from "../utils/Store";
import Cookies from "js-cookie";

// 抽离内部组件用于访问全局Context
const AppContent = ({ Component, pageProps }) => {
  const { dispatch } = useContext(Store);
  useEffect(() => {
    // 清理服务端注入的JSS样式
    const jssStyles = document.querySelector("#jss-server-side");
    if (jssStyles) {
      jssStyles.parentElement.removeChild(jssStyles);
    }
    // 客户端环境就绪后读取Cookie同步主题状态
    const darkModeCookie = Cookies.get("darkMode");
    dispatch({ 
      type: darkModeCookie === "ON" ? "DARK_MODE_ON" : "DARK_MODE_OFF" 
    });
  }, [dispatch]);

  return <Component {...pageProps} />
}

function MyApp({ Component, pageProps }) {
  return (
    <StoreProvider>
      <AppContent Component={Component} pageProps={pageProps} />
    </StoreProvider>
  );
}

export default MyApp;

useEffect内的逻辑只会在浏览器端执行,不会在服务端渲染阶段运行,从根源避免前后端渲染结果不一致的问题。

3. 验证修复效果

重启开发服务后校验:

  • 控制台不再出现Prop className did not match Server and Client报错
  • 刷新页面时Switch开关状态与Cookie存储的主题配置完全一致,不会出现先关闭再自动开启的首屏异常
  • 深色/浅色主题切换功能正常,手动刷新页面后主题状态可正常保留

内容的提问来源于stack exchange,提问作者Mahesh Yadav

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 01:36:26