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

React页面刷新后localStorage状态丢失的问题及修复方案

React中localStorage刷新后状态重置的解决方法

问题描述

我在React中使用localStorage时遇到了问题:点击按钮更新状态后,localStorage的值会同步变化,但页面刷新后,状态和localStorage都会恢复为初始值。相关代码如下:

import { useState, useEffect } from 'react';

function App() {
  // 原代码中这部分在`useVolume`自定义hook内
  const [volumes, setVolumes] = useState([0, 0, 0]);

  useEffect(() => {
    const savedVolumes = localStorage.getItem('volumes');
    if (savedVolumes) {
      const parsedVolumes = JSON.parse(savedVolumes);
      setVolumes(parsedVolumes);
    }
  }, []);

  useEffect(() => {
    localStorage.setItem('volumes', JSON.stringify(volumes));
  }, [volumes]);

  // 原代码中这部分在`useVolume`自定义hook内,包含其他更新volumes的函数
  const updateVolumes = () => {
    const newVolumes = [0, 0, 1];
    setVolumes(newVolumes);
  };

  return (
    <div className="App">
      <div>{JSON.stringify(volumes)}</div>
      <button onClick={updateVolumes}>Update Volumes</button>
    </div>
  );
}

export default App;

注:为简化示例,我将volumes、setVolumes和updateVolumes放在了App()中,实际项目里它们位于自定义hook中,因此希望将localStorage逻辑与该hook解耦。

问题原因

刷新后重置的核心原因是:组件初始化时,useState([0,0,0])会先把状态设为初始值,之后第一个useEffect才从localStorage取数据更新状态,但此时第二个useEffect会因为状态变化(从初始值到localStorage的值)再次触发,把初始值覆盖回localStorage,导致刷新后数据重置。

解决方案

1. 先解决刷新重置问题

直接在useState初始化时优先读取localStorage的值,避免后续覆盖:

import { useState, useEffect } from 'react';

function App() {
  // 初始化时先从localStorage读取,没有则用默认值
  const [volumes, setVolumes] = useState(() => {
    const saved = localStorage.getItem('volumes');
    return saved ? JSON.parse(saved) : [0, 0, 0];
  });

  // 只在volumes变化时更新localStorage
  useEffect(() => {
    localStorage.setItem('volumes', JSON.stringify(volumes));
  }, [volumes]);

  const updateVolumes = () => {
    const newVolumes = [0, 0, 1];
    setVolumes(newVolumes);
  };

  return (
    <div className="App">
      <div>{JSON.stringify(volumes)}</div>
      <button onClick={updateVolumes}>Update Volumes</button>
    </div>
  );
}

export default App;

这样初始化时状态直接取localStorage的值,不会出现初始值覆盖的问题,刷新后状态和localStorage都会保持最新值。

2. 实现localStorage逻辑与自定义hook解耦

封装一个通用的useLocalStorage hook,专门处理localStorage的读写,原useVolume hook只负责业务逻辑:

第一步:封装通用useLocalStorage hook

// hooks/useLocalStorage.js
import { useState } from 'react';

export function useLocalStorage(key, initialValue) {
  // 初始化优先读取localStorage
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error('读取localStorage失败:', error);
      return initialValue;
    }
  });

  // 更新时同步到localStorage,支持函数式更新
  const setValue = (value) => {
    try {
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.error('写入localStorage失败:', error);
    }
  };

  return [storedValue, setValue];
}

第二步:修改原useVolume hook,使用useLocalStorage

// hooks/useVolume.js
import { useLocalStorage } from './useLocalStorage';

export function useVolume() {
  // 用useLocalStorage替代普通useState,实现解耦
  const [volumes, setVolumes] = useLocalStorage('volumes', [0, 0, 0]);

  const updateVolumes = () => {
    const newVolumes = [0, 0, 1];
    setVolumes(newVolumes);
  };

  // 其他业务逻辑函数...

  return { volumes, updateVolumes };
}

第三步:在App组件中使用useVolume

import { useVolume } from './hooks/useVolume';

function App() {
  const { volumes, updateVolumes } = useVolume();

  return (
    <div className="App">
      <div>{JSON.stringify(volumes)}</div>
      <button onClick={updateVolumes}>Update Volumes</button>
    </div>
  );
}

export default App;

这样useVolume只负责音量相关的业务逻辑,localStorage的读写逻辑完全封装在useLocalStorage中,既实现了解耦,又解决了刷新重置的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 05:16:04