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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 00:36:05