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

如何结合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引用、组件实例
  • 带循环引用的对象
修复步骤
  1. 先清空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;
      }
    }
);
  1. 检查todos数组的每一项,确保没有存储不可序列化的内容,你可以在useEffect里加测试代码验证:
useEffect(() => {
  // 单独执行序列化看是否报错
  try {
    const serialized = JSON.stringify(todos);
    localStorage.setItem("todos", serialized);
  } catch (err) {
    console.error("序列化todos失败", err, todos);
  }
}, [todos]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 14:24:00