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

如何用React Context结合LocalStorage保存主题,修复切换浅色模式刷新回深色问题

问题原因与解决方案

核心问题1:LocalStorage 存储类型不匹配

LocalStorage 仅支持存储字符串类型数据,你的代码存在两处逻辑错误:

  • 初始取值时,localStorage.getItem('Mode') 返回的是字符串(比如 "false"),而你直接将其作为布尔值使用。在 JavaScript 中,非空字符串都会被判定为 true,所以当存储的是 "false" 时,初始状态会被设为 "false"(字符串),这个值在逻辑判断中等同于 true,导致刷新后自动切回深色模式。
  • 存储时直接存入布尔值,会被自动转为字符串(false → "false"),但取值阶段未做类型转换,导致状态判断混乱。

核心问题2:Context 作用域错误

AppRouter 组件直接调用 useContext(ThemeContext),但该组件并未被 ThemeContextProvider 包裹,会导致无法正确获取主题状态,甚至出现 undefined 异常。


修复后的代码

1. 修正 ThemeContextProvider

import { createContext, useEffect, useState } from "react";

export const ThemeContext = createContext()

export const ThemeContextProvider = ({ children }) => {
    // 初始值:从LocalStorage读取并转为布尔类型,默认false
    const [darkMode, setDarkMode] = useState(() => {
        const storedMode = localStorage.getItem('Mode');
        // 明确字符串转布尔:仅当存储值为"true"时才返回true
        return storedMode === 'true';
    })

    const changeTheme = () => {
        // 使用函数式更新,确保基于最新状态切换
        setDarkMode(prev => !prev)
    }

    useEffect(() => {
        // 存储时将布尔值转为标准字符串
        localStorage.setItem('Mode', darkMode.toString())
    }, [darkMode])

    return (
        <ThemeContext.Provider value={{ darkMode, changeTheme }}>
            {children}
        </ThemeContext.Provider>
    )
}

2. 修正 AppRouter 的 Context 作用域

确保所有需要使用主题状态的组件都被 ThemeContextProvider 包裹:

import React from 'react'
import { BrowserRouter, Route, Routes } from 'react-router-dom'
import Home from "../pages/Home"
import About from "../pages/About"
import Header from '../components/Header'
import { ContextProvider } from "../context/GlobalState"
import { useContext } from 'react'
import { ThemeContext, ThemeContextProvider } from '../context/ThemeContext'

// 抽离内部内容,确保在Provider作用域内使用Context
const AppContent = () => {
    const { darkMode } = useContext(ThemeContext)
    return (
        <main className={darkMode ? 'dark' : 'light'}>
            <ContextProvider>
                <BrowserRouter>
                    <Header />
                    <Routes>
                        <Route path='/' element={<Home />} />
                        <Route path='/about' element={<About />} />
                    </Routes>
                </BrowserRouter>
            </ContextProvider>
        </main>
    )
}

const AppRouter = () => {
    return (
        <ThemeContextProvider>
            <AppContent />
        </ThemeContextProvider>
    )
}

export default AppRouter

关键修复点说明

  • 类型转换:初始取值时通过 storedMode === 'true' 明确转换字符串为布尔值,避免非空字符串被误判;存储时用 toString() 统一格式。
  • Context 作用域:将所有依赖主题状态的组件放在 ThemeContextProvider 内部,确保状态可正常获取。
  • 状态更新优化:使用函数式更新 setDarkMode(prev => !prev),避免闭包导致的状态不一致问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 07:18:10