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

Next.js页面刷新时为body添加类名的实现方案

解决React/Next.js页面刷新时给body添加类名的问题

问题原因

你猜的没错,直接在组件函数体里操作document.body会失效,核心原因有两个:

  • Next.js默认是服务端渲染(SSR),服务端环境不存在document对象,这段代码在服务端执行会报错;就算到了客户端渲染阶段,组件函数执行时DOM可能还未完全挂载,操作自然无效。
  • 组件每次渲染都会执行这段代码,但settings.mode可能在组件渲染完成后才完成初始化,导致类名设置时机滞后。

解决方案

用React的useEffect钩子处理DOM操作,它会在组件挂载到客户端DOM后执行,还能监听settings.mode的变化自动同步类名,完美适配Next.js的渲染逻辑:

修改后的代码

import { useEffect } from 'react';
import { IconButton } from '@mui/material'; // 按实际组件库调整
import WeatherSunny from './icons/WeatherSunny'; // 路径按需修改
import WeatherNight from './icons/WeatherNight';

const ModeToggler = (props: Props) => {
  const { settings, saveSettings } = props;

  const handleModeChange = (mode: PaletteMode) => {
    saveSettings({ ...settings, mode });
  };

  const handleModeToggle = () => {
    const newMode = settings.mode === 'light' ? 'dark' : 'light';
    handleModeChange(newMode);
  };

  // 监听mode变化,同步body类名
  useEffect(() => {
    if (settings.mode === 'dark') {
      document.body.classList.add('mode-dark');
    } else {
      document.body.classList.remove('mode-dark');
    }
  }, [settings.mode]); // 只有mode变化时才执行

  return (
    <IconButton color='inherit' aria-haspopup='true' onClick={handleModeToggle}>
      {settings.mode === 'dark' ? <WeatherSunny /> : <WeatherNight />}
    </IconButton>
  );
};

export default ModeToggler;

关键说明

  • useEffect的依赖数组[settings.mode]确保只有当settings.mode变化时,才会执行内部DOM操作,保证类名和状态完全同步,不管是手动切换还是页面刷新都能生效。
  • 移除handleModeToggle里的直接DOM操作,让状态驱动UI变化,符合React的设计理念,避免状态和DOM不一致的问题。
  • 在Next.js中,useEffect只会在客户端执行,彻底规避服务端document不存在的报错。

额外优化(可选)

如果你的settings是从本地存储读取的,建议在组件初始化时先读取本地存储的mode,确保刷新后状态正确,再通过useEffect同步类名:

import { useEffect, useState } from 'react';

const ModeToggler = (props: Props) => {
  const [localMode, setLocalMode] = useState<PaletteMode>(() => {
    // 客户端初始化时读取localStorage
    if (typeof window !== 'undefined') {
      return localStorage.getItem('mode') as PaletteMode || 'light';
    }
    return 'light';
  });

  const handleModeChange = (mode: PaletteMode) => {
    setLocalMode(mode);
    saveSettings({ ...settings, mode });
    localStorage.setItem('mode', mode);
  };

  useEffect(() => {
    if (localMode === 'dark') {
      document.body.classList.add('mode-dark');
    } else {
      document.body.classList.remove('mode-dark');
    }
  }, [localMode]);

  // 其余代码保持不变...
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:24:28