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

Next.js/React动态设置背景色时出现Prop className不匹配报错如何解决

问题原因

这个报错是Next.js 水合(Hydration)不匹配导致的:

  • Next.js 服务端渲染(SSR/SSG)阶段无法访问浏览器专属的 localStorage API,服务端生成的 <style jsx> 样式内容和客户端读取 localStorage 后生成的样式内容不一致
  • styled-jsx 会根据样式内容生成唯一的 className,两端 className 不一致就触发了该报错。硬编码颜色时服务端和客户端样式完全一致,因此不会报错
解决方案

核心思路

保证服务端和客户端首次渲染的内容完全一致,等待客户端挂载完成后再加载 localStorage 中的动态主题配置。


完整修改代码

如果你使用 Pages 路由

import { useState, useEffect } from 'react';

function Theme() {
  // 新增挂载状态,服务端和客户端首次渲染时都为 false
  const [isMounted, setIsMounted] = useState(false);
  const [dark, setDark] = useState(false);
  // 首次渲染用默认颜色,避免两端不一致
  const [themeColor, setThemeColor] = useState('white');

  useEffect(() => {
    // 客户端挂载完成后再读取 localStorage
    setIsMounted(true);
    const savedColor = window.localStorage.getItem('color') || 'white';
    setThemeColor(savedColor);
    setDark(savedColor === '#141526');
  }, []);

  function toggleTheme() {
    setDark(prev => {
      const newDark = !prev;
      const newColor = newDark ? '#141526' : 'white';
      setThemeColor(newColor);
      window.localStorage.setItem('color', newColor);
      console.log(newDark ? 'enabled' : 'disabled');
      return newDark;
    });
  }

  // 未挂载时渲染和服务端一致的默认样式,避免水合不匹配
  if (!isMounted) {
    return (
      <div>
        <style jsx global className='theme'>{`
          body {
            background: white;
          }
        `}</style>
        <label htmlFor='dark'>Dark theme</label>
        <input type='checkbox' name='dark' id='dark' disabled />
      </div>
    )
  }

  return (
    <div>
      <style jsx global className='theme'>{`
        body {
          background: ${themeColor};
        }
      `}</style>
      <label htmlFor='dark'>Dark theme</label>
      <input type='checkbox' name='dark' id='dark' checked={dark} onClick={toggleTheme} />
    </div>
  );
}

export default Theme;

如果你使用 App 路由(Next.js 13+)

在组件顶部添加 'use client' 指令即可,其余修改逻辑和 Pages 路由一致:

'use client';
// 后续代码和上面Pages路由的实现逻辑完全相同

优化建议

你也可以改用CSS变量实现主题切换,避免动态修改 <style jsx> 内容,进一步降低水合不匹配的概率:

  1. 在全局CSS中定义默认和暗色主题的变量
:root {
  --bg-color: white;
}
:root.dark {
  --bg-color: #141526;
}
body {
  background: var(--bg-color);
}
  1. 主题切换时只需要给 document.documentElement 增删 dark 类即可,不需要动态生成样式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 13:36:03