如何在React+Next.js+MUI V5项目中实现Local Storage持久化暗黑模式切换
实现方案
你只需要修改ThemeContext组件的逻辑即可,原有AppBar的切换代码不需要做任何调整,修改后的完整代码如下:
import { createContext, useMemo, useState, useEffect } from 'react' import { createTheme, ThemeProvider } from '@mui/material/styles' export const ColorModeContext = createContext({ toggleColorMode: () => {} }) const ThemeContext = ({ children }) => { // 初始默认设为dark,避免SSR和客户端渲染结果不一致导致的hydration报错 const [mode, setMode] = useState('dark') // 客户端挂载后从本地存储读取之前保存的模式 useEffect(() => { const savedMode = localStorage.getItem('mui-color-mode') if (savedMode) { setMode(savedMode) } // 可选优化:没有保存的模式时优先匹配系统暗黑偏好 // else { // const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches // setMode(prefersDark ? 'dark' : 'light') // } }, []) const colorMode = useMemo( () => ({ toggleColorMode: () => { setMode((prevMode) => { const newMode = prevMode === 'light' ? 'dark' : 'light' // 切换时将新模式存入本地存储 localStorage.setItem('mui-color-mode', newMode) return newMode }) }, }), [] ) const theme = useMemo( () => createTheme({ palette: { mode, primary: { light: '#757ce8', main: '#3f50b5', dark: '#002884', contrastText: '#fff', }, secondary: { light: '#ff7961', main: '#f44336', dark: '#ba000d', contrastText: '#000', }, }, }), [mode] ) return ( <ColorModeContext.Provider value={colorMode}> <ThemeProvider theme={theme}>{children}</ThemeProvider> </ColorModeContext.Provider> ) } export default ThemeContext
核心修改说明
- 新增
useEffect在客户端挂载后才读取本地存储,避开Next.js服务端渲染阶段无法访问window的问题 - 切换模式的逻辑中同步将新状态存入
localStorage,刷新页面后会自动读取之前保存的模式
可选优化
如果想要避免首次加载时的主题闪烁,可以在Next.js的_document.js中注入内联脚本,提前读取本地存储的模式值给html根元素设置对应背景色,不需要等React组件挂载后再切换。
内容的提问来源于stack exchange,提问作者Chan Lay
相关产品推荐
相关产品推荐

