React.js开发TodoList刷新页面后待办项丢失问题解决
问题根因
刷新后待办项消失是useEffect执行顺序导致的存储覆盖问题:
- React组件首次挂载时,所有
useEffect会严格按照代码中的声明顺序依次执行 - 你的代码里先声明了依赖
list的持久化effect:首次执行时list是初始空数组[],会直接把空值写入LocalStorage,把之前存好的待办数据完全覆盖 - 等后面声明的读取LocalStorage的effect执行时,读到的已经是刚被覆盖的空数组,自然无法恢复之前的待办内容
修复方案
推荐直接在useState初始化阶段就读取LocalStorage作为list的初始值,删掉单独用来做初始化读取的useEffect,从根源上避免首次渲染空值覆盖存储的问题,这也是React状态持久化的通用最佳实践。
如果你不想调整初始化逻辑,把读取LocalStorage的useEffect移到持久化effect的前面,让读取逻辑先执行也能临时解决问题,但这种方案强依赖effect的声明顺序,后续调整代码时很容易再次出问题,不推荐使用。
修复后代码
import React, { useState, useEffect } from 'react' import TodoList from './TodoList.jsx' const AddTodo = () => { const [newTodo, setNewTodo] = useState('') // 惰性初始化:仅在组件首次渲染时读取一次LocalStorage const [list, setList] = useState(() => { const storedData = localStorage.getItem('list') return storedData ? JSON.parse(storedData) : [] }) const handleSubmit = () => { // 新增空值校验,避免添加空内容/全空格的无效待办 if (!newTodo.trim()) return const todoItem = { id: Math.floor(Math.random() * 10000), value: newTodo.trim() } setList([...list, todoItem]) setNewTodo('') } // list变化时自动同步到LocalStorage,首次执行时list已是有效初始值,不会覆盖旧数据 useEffect(() => { localStorage.setItem("list", JSON.stringify(list)) }, [list]) return ( <div className="input_container"> <form onSubmit={(e) => e.preventDefault()}> <input type="text" onChange={e => setNewTodo(e.target.value)} className="todo-input" placeholder="Write Todo.." value={newTodo} name="text" /> <button onClick={handleSubmit} className="add-todo-button" > Add Todo </button> </form> <TodoList list={list} newTodo={newTodo}/> </div> ) } export default AddTodo
额外说明
- 这里用了
useState的惰性初始化语法(传函数而不是直接传值),读取LocalStorage的逻辑只会在组件首次渲染时执行一次,相比在effect里读取性能更好 - 新增的输入trim校验可以避免用户误输入空内容生成无效待办,你可以根据自己的需求决定是否保留
- 给
onClick直接传handleSubmit函数引用即可,不需要额外包一层箭头函数,能减少不必要的重渲染
内容的提问来源于stack exchange,提问作者SwedieK
相关产品推荐
相关产品推荐

