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
相关产品推荐
相关产品推荐

