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

React中Local Storage刷新后丢失暗黑模式状态的原因及优化方案

React暗黑模式状态刷新丢失问题分析与解决方案

问题原因

  • localStorage类型不匹配:localStorage仅支持存储字符串,你直接存入布尔值true/false会被自动转为字符串"true"/"false"。初始化时localStorage.getItem('darkMode') || false的逻辑有问题——当存储的是"false"时,非空字符串会被判定为真值,导致darkMode初始值是字符串而非布尔值,后续和布尔值true比较时逻辑错乱,状态同步失效。
  • mode状态未同步初始化:页面刷新时,mode始终使用默认的{bg: 'light', variant: 'light'},没有根据localStorage中的darkMode值更新,导致样式不匹配,极端情况下可能因mode未正确初始化出现bg未定义的错误。
  • 状态更新逻辑冗余:toggle函数中手动同步mode、darkMode和localStorage,逻辑分散且容易出现异步更新不一致的问题。

优化实现方式

基础修正版本

先修复核心的类型问题和状态同步逻辑:

import { useState, useEffect } from 'react';

function YourComponent() {
  // 函数式初始化,避免重复读取localStorage,正确解析布尔值
  const [darkMode, setDarkMode] = useState(() => {
    const stored = localStorage.getItem('darkMode');
    return stored !== null ? JSON.parse(stored) : false;
  });

  const [mode, setMode] = useState({ bg: 'light', variant: 'light' });

  // 监听darkMode变化,同步更新mode和localStorage
  useEffect(() => {
    setMode(darkMode ? { bg: 'dark', variant: 'dark' } : { bg: 'light', variant: 'light' });
    localStorage.setItem('darkMode', JSON.stringify(darkMode));
  }, [darkMode]);

  const toggleDarkMode = () => {
    // 基于前序状态取反,避免依赖当前快照
    setDarkMode(prev => !prev);
  };

  return (
    <div className={`bg-${mode.bg}`}>
      <button onClick={toggleDarkMode}>
        {darkMode ? '切换到浅色模式' : '切换到深色模式'}
      </button>
    </div>
  );
}

高效复用的自定义Hook方案

如果多个组件需要使用暗黑模式,建议封装成自定义Hook,减少重复代码:

import { useState, useEffect } from 'react';

function useDarkMode() {
  // 初始化时读取并解析localStorage
  const [darkMode, setDarkMode] = useState(() => {
    const stored = localStorage.getItem('darkMode');
    return stored !== null ? JSON.parse(stored) : false;
  });

  useEffect(() => {
    // 同步到localStorage
    localStorage.setItem('darkMode', JSON.stringify(darkMode));
    // 直接操作根元素class,配合CSS变量或工具类实现样式切换(推荐)
    document.documentElement.classList.toggle('dark', darkMode);
  }, [darkMode]);

  // 封装切换函数
  const toggleDarkMode = () => setDarkMode(prev => !prev);

  return { darkMode, toggleDarkMode };
}

// 组件中使用
function App() {
  const { darkMode, toggleDarkMode } = useDarkMode();

  return (
    <div className={darkMode ? 'dark-theme' : 'light-theme'}>
      <button onClick={toggleDarkMode}>
        {darkMode ? '浅色模式' : '深色模式'}
      </button>
    </div>
  );
}

这个方案的优势:

  • 逻辑集中,所有组件可复用,无需重复编写状态同步代码
  • 直接操作根元素class,无需维护额外的mode状态,减少状态冗余
  • 初始化和更新逻辑分离,避免异步状态不一致问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 01:40:38