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

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; 

问题原因

  1. API拼写错误:所有调用本地存储的代码都错误使用了小写s的localstorage,而标准浏览器API是驼峰命名的localStorage(大写S)。部署环境下代码严格执行,未定义的localstorage变量会导致getItem调用失败,最终JSON.parse处理错误值后返回null,使favoriteCats状态变为null,当组件访问favoriteCats.length时触发报错。
  2. 重复状态覆盖:初始的useState已经完成从本地存储加载数据的逻辑,但后续又添加了一个空依赖的useEffect,再次尝试设置favoriteCats状态。即使拼写正确,这个操作也会在组件挂载时覆盖初始状态,若本地存储无数据,会将状态设置为null而非初始的空数组。

修复方案

  1. 修正API拼写:将所有localstorage替换为localStorage。
  2. 移除重复的useEffect:删除那个空依赖的useEffect,避免覆盖初始状态。
  3. 增加错误处理:在读写本地存储时添加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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 16:45:46