React项目部署至Github Pages时出现TypeError:无法读取null的length属性
useState从localStorage加载变量在Github Pages部署后变为null的问题排查
问题现象
本地开发服务器运行正常,但部署到Github Pages后,通过useState从localStorage加载的favoriteCats变量变为null,触发「Uncaught TypeError: Cannot read properties of null (reading 'length')」错误,替换为sessionStorage后问题依旧。
相关代码
import {useEffect, useState} from "react"; import {Route, Routes} from "react-router-dom"; import axios from 'axios' import './App.css'; import Header from "../Header/Header"; import CatsList from "../CatsList/CatsList"; import FavoriteCats from "../CatsList/FavoriteCats"; function App() { const [catsList, setCatsList] = useState([]); const [favoriteCats, setFavoriteCats] = useState(() => { const cats = JSON.parse(localstorage.getItem("favoriteCats")); if (cats !== null) { return cats } else return [] }); const [currentPage, setCurrentPage] = useState(1); const [fetching, setFetching] = useState(true); useEffect(() => { document.addEventListener('scroll', scrollHandler) return function () { document.removeEventListener('scroll', scrollHandler) } }, []) useEffect(() => { if (fetching) { axios.get(`https://api.thecatapi.com/v1/images/search?format=json&limit=15&_page=${currentPage}`, {headers: {"x-api-key": "03b1c2d3-fb3d-4363-9e71-949a93d8d9f8"}}) .then(res => { setCatsList(catsList => [...catsList, ...res.data]) setCurrentPage(prevState => prevState + 1) }) .finally(() => setFetching(false)) } }, [fetching]) const scrollHandler = (e) => { if (e.target.documentElement.scrollHeight - (e.target.documentElement.scrollTop + window.innerHeight) < 100) { setFetching(true) } } useEffect(() => { setFavoriteCats(JSON.parse(localstorage.getItem('favoriteCats'))) }, []); useEffect(() => { localstorage.setItem('favoriteCats', JSON.stringify(favoriteCats)); },[favoriteCats]) return ( <div className="App"> <Header /> <Routes> <Route exact path='/' element={<CatsList list={catsList} setFavoriteCats={setFavoriteCats} favoriteCats={favoriteCats}/>} /> <Route path={'/favorite'} element={<FavoriteCats favoriteCats={favoriteCats} setFavoriteCats={setFavoriteCats}/>} /> </Routes> </div> ); } export default App;
问题原因
- API拼写错误:所有调用本地存储的代码都错误使用了小写
s的localstorage,而标准浏览器API是驼峰命名的localStorage(大写S)。部署环境下代码严格执行,未定义的localstorage变量会导致getItem调用失败,最终JSON.parse处理错误值后返回null,使favoriteCats状态变为null,当组件访问favoriteCats.length时触发报错。 - 重复状态覆盖:初始的useState已经完成从本地存储加载数据的逻辑,但后续又添加了一个空依赖的useEffect,再次尝试设置
favoriteCats状态。即使拼写正确,这个操作也会在组件挂载时覆盖初始状态,若本地存储无数据,会将状态设置为null而非初始的空数组。
修复方案
- 修正API拼写:将所有
localstorage替换为localStorage。 - 移除重复的useEffect:删除那个空依赖的useEffect,避免覆盖初始状态。
- 增加错误处理:在读写本地存储时添加try/catch,避免JSON解析或存储失败导致的异常,同时确保状态始终为数组类型:
修正后的核心代码示例:
const [favoriteCats, setFavoriteCats] = useState(() => { try { const cats = JSON.parse(localStorage.getItem("favoriteCats")); // 确保返回数组,避免null或undefined return Array.isArray(cats) ? cats : []; } catch (error) { console.error('加载收藏数据失败:', error); return []; } }); // 保存收藏数据的useEffect useEffect(() => { try { localStorage.setItem('favoriteCats', JSON.stringify(favoriteCats)); } catch (error) { console.error('保存收藏数据失败:', error); } },[favoriteCats])
内容的提问来源于stack exchange,提问作者Evgeniya Lashukova
相关产品推荐
相关产品推荐

