
本文详解如何正确使用 localstorage 与 react 的 useeffect 配合,解决待办列表(todolist)刷新后数据丢失的问题,重点规避 json.parse 解析 null 或无效字符串导致的崩溃,并确保状态初始化与存储同步。
本文详解如何正确使用 localstorage 与 react 的 useeffect 配合,解决待办列表(todolist)刷新后数据丢失的问题,重点规避 json.parse 解析 null 或无效字符串导致的崩溃,并确保状态初始化与存储同步。
在 React 中利用 localStorage 持久化待办列表数据是一个常见需求,但初学者常因未处理边缘情况而失败。你提供的代码存在两个关键隐患:
- 首次读取时 getItem("todoStorage") 可能返回 null,直接 JSON.parse(null) 会抛出 SyntaxError,导致组件渲染失败;
- 初始 useState([]) 与 useEffect 中 setTodos(JSON.parse(data)) 同步执行时,若 data 为 null 或非法 JSON,状态将被设为 undefined,后续 JSON.stringify(undefined) 存入 localStorage,进一步破坏数据一致性。
✅ 正确做法是:安全解析 + 显式兜底 + 条件写入。以下是优化后的完整实现:
import { useState, useEffect } from 'react';
function TodoList() {
// 初始化状态为 null,便于区分“未加载”和“空数组”
const [todos, setTodos] = useState(null);
// ✅ 第一个 useEffect:初始化读取(仅执行一次)
useEffect(() => {
try {
const saved = window.localStorage.getItem('todoStorage');
// 安全解析:仅当 saved 存在且为合法 JSON 数组时才使用,否则回退为空数组
const parsed = saved ? JSON.parse(saved) : [];
setTodos(Array.isArray(parsed) ? parsed : []);
} catch (err) {
console.warn('Failed to parse localStorage todo data:', err);
setTodos([]); // 解析失败时仍保证状态为有效数组
}
}, []);
// ✅ 第二个 useEffect:响应式写入(仅当 todos 确实变化时触发)
useEffect(() => {
if (todos !== null) {
try {
window.localStorage.setItem('todoStorage', JSON.stringify(todos));
} catch (err) {
console.error('Failed to save todos to localStorage:', err);
}
}
}, [todos]);
// 其余业务逻辑(添加、删除、切换完成等)保持不变...
const addTodo = (text) => {
setTodos(prev => [...prev, { id: Date.now(), text, completed: false }]);
};
return (
<div>
{/* 渲染逻辑 */}
<ul>
{todos?.map(todo => (
<li key="{todo.id}">{todo.text} — {todo.completed ? '✓' : '○'}</li>
))}
</ul>
<button onclick="{()"> addTodo('New task')}>Add</button>
</div>
);
}
export default TodoList;
? 关键要点总结:
- 永远用 try...catch 包裹 JSON.parse() 和 localStorage.setItem(),避免因存储损坏或配额超限导致应用崩溃;
- 状态初始化推荐 useState(null) 而非 useState([]),可清晰区分“尚未读取”与“已读取为空数组”,便于调试;
- 写入前校验 todos !== null,避免在初始化阶段(todos 还是 null 时)错误触发存储;
- 无需手动判断 todos.length > 0 再写入——只要状态变更(包括从 [] 变为 []),useEffect 依赖数组机制自然触发,且空数组 JSON.stringify([]) 是完全合法的操作。
遵循以上模式,你的待办列表即可在任意刷新、关闭再打开后,精准还原全部任务状态,真正实现客户端持久化。











