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

Next.js+MUI5通过Cookie切换明暗模式报className不匹配警告

问题根因

控制台抛出的Prop 'className' did not match是典型的SSR/SSG 水合不匹配错误,和当前Redux初始化主题状态的逻辑直接相关:

  • 服务端预渲染页面时,运行环境是Node.js,无法读取浏览器端存储的Cookie,此时Cookies.get('darkMode')返回undefined,Redux中darkMode初始值永远为false,最终服务端生成的所有DOM节点都是浅色模式对应的className。
  • 页面下发到浏览器后,客户端JS加载运行,Redux初始化时成功读取到本地Cookie里的darkMode=ON,状态变为true,首次客户端渲染生成的DOM全是深色模式对应的className。
  • React做水合校验时,发现客户端生成的DOM className和服务端返回的初始DOM完全对不上,就会抛出上述警告,水合过程中断。导航栏作为布局层最先挂载的组件,可能在水合校验抛出错误前已经应用了深色样式,后续组件因为水合失败停止渲染,就出现了仅导航栏变深色、后续内容不加载的现象。
修复方案

核心原则是保证服务端和客户端首次渲染的状态、DOM结构完全一致,等水合完成后再同步客户端本地存储的主题状态:

  1. 调整Redux主题切片的初始值逻辑,移除初始化时直接读取Cookie的代码,统一将darkMode初始值设为false,从根源上消除两端初始状态不一致的问题,同时新增一个显式设置主题状态的action:
import Cookies from 'js-cookie';
import { createSlice } from '@reduxjs/toolkit'

const initialState = {
  darkMode: false, // 两端初始值统一,避免水合不匹配
}

export const DarkModeSlice = createSlice({
  name: 'darkMode',
  initialState,
  reducers: {
    // 新增显式设置主题的action,用于挂载后同步本地存储状态
    setDarkMode: (state, action) => {
      state.darkMode = action.payload
    },
    toggleDarkMode: (state) => {
      let newDarkMode = !state.darkMode;
      Cookies.set("darkMode", newDarkMode ? "ON" : "OFF");
      state.darkMode = newDarkMode
    }
  },
})

export const { toggleDarkMode, setDarkMode } = DarkModeSlice.actions

export default DarkModeSlice.reducer
  1. 在应用入口组件(Next.js对应_app.js/tsx,纯React项目对应根App.js/tsx)中,通过useEffect在客户端挂载完成、水合结束后,再读取Cookie中存储的主题状态,同步到Redux中。useEffect只会在客户端执行,不会影响服务端渲染的初始结果:
import { useEffect } from 'react'
import { useDispatch } from 'react-redux'
import Cookies from 'js-cookie'
import { setDarkMode } from '@/store/features/darkModeSlice' // 替换成实际的切片路径

export default function App({ Component, pageProps }) {
  const dispatch = useDispatch()

  useEffect(() => {
    // 水合完成后再同步本地存储的主题配置
    const savedDarkMode = Cookies.get('darkMode') === 'ON'
    dispatch(setDarkMode(savedDarkMode))
  }, [dispatch])

  return <Component {...pageProps} />
}
  1. (可选优化)如果要修复首次进入页面时的主题闪烁问题,可以在项目入口HTML的<head>标签内加入一段提前执行的内联脚本,在页面资源加载前就读取Cookie给根节点加上主题标识类,配合MUI的主题配置提前生效,这段脚本不影响React水合逻辑,因为它操作的是React挂载根节点之外的属性。

内容的提问来源于stack exchange,提问作者Ahmed Azzam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:36:20