React待办应用部署Netlify报JSON Unexpected token u解析错误
问题根因
- 核心bug在
getTodoFromLocal函数的返回逻辑缺失:- 线上首次访问时浏览器无历史localStorage数据,函数判断
localStorage.getItem("todos") === null的分支,只执行了往存储写入空数组的操作,没有写return语句,函数默认返回undefined useState(getTodoFromLocal())拿到undefined作为todos初始值后,立刻触发依赖todos的useEffect执行saveToLocal:此时JSON.stringify(undefined)返回undefined,转成字符串存入localStorage的值就是"undefined"- 后续读取存储时,
JSON.parse("undefined")就会抛出Unexpected token u in JSON at position 0错误——字符串首字符是u,不属于合法JSON格式
- 线上首次访问时浏览器无历史localStorage数据,函数判断
- 两个隐藏逻辑漏洞:
- try/catch块捕获解析错误后仅打印日志,没有返回兜底空数组,依然会返回undefined
- 首次加载时写的
useEffect(() => { getTodoFromLocal(); }, [])完全无效,函数返回值没有被用来更新todos状态
- 本地运行正常是因为开发阶段浏览器已经存过合法的todos数组数据,一直走else分支正常解析返回,不会触发if分支无返回的bug;线上部署后是全新访问域名,无历史存储数据,直接触发逻辑漏洞。
修复方案
只需要修改App.js的相关逻辑即可,其余组件无需改动:
- 重写
getTodoFromLocal函数,保证所有分支都明确返回数组类型,增加多层兜底 - 删除无效的首次加载useEffect调用
- 给存储写入逻辑增加类型校验,避免异常值写入localStorage
修改后的核心代码如下:
// get data from local const getTodoFromLocal = () => { try { const localTodo = localStorage.getItem("todos"); // 无存储值时初始化存储并返回空数组 if (localTodo === null) { localStorage.setItem("todos", JSON.stringify([])); return []; } const parsedTodo = JSON.parse(localTodo); // 兜底:解析结果非数组时返回空数组,避免后续map执行报错 return Array.isArray(parsedTodo) ? parsedTodo : []; } catch (error) { console.log("本地存储解析失败,已重置:", error); // 解析出错时清空异常存储值,返回空数组 localStorage.setItem("todos", JSON.stringify([])); return []; } } const App = () => { // states const [inputText, setInputText] = useState(""); const [todos, setTodos] = useState(getTodoFromLocal()); const [status, setStatus] = useState("all"); const [filteredTodo, setFilteredTodo] = useState([]); // 删除以下无效的useEffect代码 // useEffect(() => { // getTodoFromLocal(); // }, []) // 页面加载、todos或status变化时执行过滤和存储 useEffect(() => { filterHandler(); saveToLocal(); }, [todos, status]) // functions const filterHandler = () =>{ switch (status) { case 'completed': setFilteredTodo(todos.filter(todo => todo.completed === true)); break; case 'incompleted': setFilteredTodo(todos.filter(todo => todo.completed === false)); break; default: setFilteredTodo(todos); break; } } // 保存数据到本地存储 const saveToLocal = () => { // 仅当todos是数组时才写入存储,避免异常值污染 if (Array.isArray(todos)) { localStorage.setItem("todos", JSON.stringify(todos)); } }; // 其余return渲染逻辑保持不变即可 }
修改完成后重新部署到Netlify,首次访问会自动初始化空的待办列表,刷新页面数据持久化正常,不会再出现JSON解析报错。
内容的提问来源于stack exchange,提问作者Mehreen
相关产品推荐
相关产品推荐

