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

页面刷新后localStorage未保存数据?React状态重置为空数组问题

问题:刷新网站后state重置为空数组

刷新网站后,history状态会重置为空数组。已通过console.log调试确认:history能正常保存到localStorage,也能正常从localStorage读取,但读取后history似乎被重新设置为空数组。

原代码:

import { useState, useRef, useEffect } from 'react'
import './styles.css'
import History from './History'

const LOCALSTORAGEKEY = './finance/src/app/12321'; 

function App() {
  const [history, setHistory] = useState([]);
  const amnt = useRef();
  const item = useRef();

  useEffect(()=>{
    const stor = JSON.parse(localStorage.getItem(LOCALSTORAGEKEY));
    if (stor) setHistory(stor)
  },[])
  useEffect(()=>{
    if(history){    
    console.log(JSON.stringify(history))
    localStorage.setItem(LOCALSTORAGEKEY,JSON.stringify(history))
    }    
  },[history])
  const now = new Date(); 

  const handleNewamnt = () =>{
    
    setHistory(prev=>{
      return([...prev, {'id':item.current.value ,'item': item.current.value, 'amnt': amnt.current.value, 'date': JSON.stringify(now) }]);
    })

    item.current.value = ''
    amnt.current.value = ''
  };


  return (
    <>
      <History  history_object= {history}/>

      <input placeholder='amount' type='number' ref={amnt} />
      <input placeholder='item' type='text' ref={item} />
      <button onClick={handleNewamnt}>confirm </button>

    </>
       

  )
}


export default App

解决方案

问题原因

  1. useEffect执行顺序冲突:组件挂载时,依赖history的第二个useEffect会先于第一个useEffect的状态更新生效,把初始的空数组[]存入localStorage,覆盖了原本存储的有效数据。
  2. 状态初始化时机滞后:原本通过useEffect在组件挂载后读取localStorage设置状态,导致组件初始渲染时状态是空数组,后续才更新,期间可能触发不必要的存储操作。

修改后的代码

import { useState, useRef, useEffect } from 'react'
import './styles.css'
import History from './History'

// 简化localStorage的key命名,避免特殊字符问题
const LOCALSTORAGEKEY = 'finance-history'; 

function App() {
  // 直接在useState初始化时从localStorage读取数据,避免异步更新的问题
  const [history, setHistory] = useState(() => {
    const storedData = localStorage.getItem(LOCALSTORAGEKEY);
    return storedData ? JSON.parse(storedData) : [];
  });
  
  const amnt = useRef();
  const item = useRef();

  // 仅在history变化时保存到localStorage,无需多余判断
  useEffect(()=>{
    localStorage.setItem(LOCALSTORAGEKEY, JSON.stringify(history));
  },[history])

  const handleNewamnt = () =>{
    // 点击时才生成当前时间,避免组件初始化时时间固定
    const now = new Date();
    setHistory(prev=>{
      return([...prev, {'id': item.current.value ,'item': item.current.value, 'amnt': amnt.current.value, 'date': JSON.stringify(now) }]);
    })

    item.current.value = ''
    amnt.current.value = ''
  };


  return (
    <>
      <History  history_object= {history}/>

      <input placeholder='amount' type='number' ref={amnt} />
      <input placeholder='item' type='text' ref={item} />
      <button onClick={handleNewamnt}>confirm </button>

    </>
       

  )
}


export default App

关键修改点

  • 状态初始化优化:将localStorage的读取逻辑移到useState的初始化函数中,组件挂载时直接获取正确的初始状态,避免异步更新导致的状态滞后。
  • 简化localStorage键名:替换带有路径的复杂键名,避免潜在的存储键名冲突或解析问题。
  • 修复时间生成逻辑:将now = new Date()移到handleNewamnt函数内部,确保每次点击按钮时生成的是当前时间,而不是组件初始化时的固定时间。
  • 移除无效判断:第二个useEffect中的if(history)判断无意义(空数组在JS中是真值),直接保存状态即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 14:45:39