如何结合useReducer钩子使用localStorage?Todo应用存储时报跨源错怎么解决?
问题原因与解决方案
你看到的跨源错误提示不是实际的错误原因,这是React开发模式下的通用提示:当页面存在未捕获的运行时错误、且React脚本和你本地开发脚本的源不同时,浏览器安全策略会阻止React获取具体错误内容,才会显示这个提示。你可以直接打开浏览器开发者工具的「控制台」面板,就能看到真实的报错信息。
结合你的使用场景,大概率是以下两个原因导致的:
1. localStorage旧数据结构不匹配
你之前给计数器应用做本地存储时,如果也用了"todos"作为存储key,那么localStorage里现存的旧值是数字类型,和你当前Todo应用需要的{todos: [], todoCount: 0}对象结构完全不匹配。
你在初始化时直接JSON.parse(localStorage.getItem("todos")) || initial,如果旧值是数字,JSON.parse返回的是合法数字,不会走|| initial的 fallback 逻辑,后续解构[{ todos, todoCount }]时,相当于从数字类型上读取todos和todoCount属性,直接抛出运行时错误。
2. Todo项包含不可序列化的内容
计数器应用的状态是纯数字,可以正常被JSON.stringify处理,但如果你的Todo项里存储了不可序列化的值,也会触发报错:
- 事件处理函数、Symbol类型值
- React元素、ref引用、组件实例
- 带循环引用的对象
修复步骤
- 先清空localStorage里的冲突旧值,打开浏览器控制台执行:
localStorage.removeItem("todos")
刷新页面后验证是否恢复正常。
2. 给初始化逻辑加结构校验,避免旧数据或者异常数据导致崩溃:
const [{ todos, todoCount }, dispatch] = useReducer( reducer, { todos: [], todoCount: 0 }, (initial) => { const savedVal = localStorage.getItem("todos"); if (!savedVal) return initial; try { const parsed = JSON.parse(savedVal); // 校验返回值结构是否符合预期 if (Array.isArray(parsed.todos) && typeof parsed.todoCount === 'number') { return parsed; } // 结构异常则清空无效数据 localStorage.removeItem("todos"); return initial; } catch (err) { // 解析失败也清空无效数据 localStorage.removeItem("todos"); return initial; } } );
- 检查todos数组的每一项,确保没有存储不可序列化的内容,你可以在useEffect里加测试代码验证:
useEffect(() => { // 单独执行序列化看是否报错 try { const serialized = JSON.stringify(todos); localStorage.setItem("todos", serialized); } catch (err) { console.error("序列化todos失败", err, todos); } }, [todos]);
内容的提问来源于stack exchange,提问作者adizh
相关产品推荐
相关产品推荐

