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

ReactJS页面刷新后Pokemon列表数据消失问题求助

问题分析与解决方案

你的核心问题在于第二个useEffect的依赖数组为空,导致它只会在组件首次挂载时执行一次。此时第一个useEffect里的异步fetch还没完成,pokemonList还是初始的空数组,所以populateRenderedList生成的是空列表。当后续pokemonList被异步请求填充后,第二个useEffect不会重新执行,renderedList也就一直保持为空。

另外,renderedList属于派生状态——它完全由pokemonList计算而来,根本不需要用useState存储。之前不用useState时能正常工作,就是因为每次渲染都会基于最新的pokemonList重新计算列表内容。

方案一:移除renderedList的状态存储(推荐)

直接在渲染阶段调用populateRenderedList,这样每次pokemonList更新时都会自动生成最新的渲染列表:

function PokemonList(props) {
  const [pokemonList, setPokemonList] = useState([]);
  const [isFetched, setIsFetched] = useState(false);

  useEffect(() => {
    fetch(raw)
      .then((r) => r.text())
      .then((text) => {
        setPokemonList(text.split("\n"));
        setIsFetched(true);
      });
  }, []);

  // 直接在渲染时计算派生状态
  const renderedList = populateRenderedList(pokemonList);

  return !isFetched ? null : (
    <div className="list">
      {renderedList}
      <PaginationBar listSize={renderedList.length} list={renderedList} />
    </div>
  );
}

function populateRenderedList(pokemonList) {
  const pokemonAPI = "https://pokeapi.co/api/v2/pokemon-form/";
  // 过滤空行(避免split后出现空字符串项)
  return pokemonList.filter(Boolean).map((pokemonName) => (
    <a 
      key={pokemonName} // 必须添加唯一key,React列表渲染要求
      className="pokemonLink" 
      href={`${pokemonAPI}${pokemonName.toLowerCase()}`}
    >
      <PokemonDiv name={pokemonName.toLowerCase()} />
      <h3>{pokemonName}</h3>
    </a>
  ));
}

方案二:修正useEffect的依赖数组(不推荐,因为没必要存派生状态)

如果你非要用useState存储renderedList,需要把pokemonList加入第二个useEffect的依赖数组,确保pokemonList更新时重新计算:

function PokemonList(props) {
  const [pokemonList, setPokemonList] = useState([]);
  const [isFetched, setIsFetched] = useState(false);
  const [renderedList, setRenderedList] = useState([]);

  useEffect(() => {
    fetch(raw)
      .then((r) => r.text())
      .then((text) => {
        setPokemonList(text.split("\n"));
        setIsFetched(true);
      });
  }, []);

  // 添加pokemonList到依赖数组
  useEffect(() => {
    setRenderedList(populateRenderedList(pokemonList));
  }, [pokemonList]);

  return !isFetched ? null : (
    <div className="list">
      {renderedList}
      <PaginationBar listSize={renderedList.length} list={renderedList} />
    </div>
  );
}

// 同样要给列表项添加key,并过滤空行
function populateRenderedList(pokemonList) {
  const pokemonAPI = "https://pokeapi.co/api/v2/pokemon-form/";
  const temp = [];

  pokemonList.filter(Boolean).forEach((pokemonName) => {
    let renderedPokemon = (
      <a 
        key={pokemonName}
        className="pokemonLink" 
        href={`${pokemonAPI}${pokemonName.toLowerCase()}`}
      >
        <PokemonDiv name={pokemonName.toLowerCase()} />
        <h3>{pokemonName}</h3>
      </a>
    );

    temp.push(renderedPokemon);
  });

  return temp;
}

额外注意事项

  • 列表渲染必须给每个子项添加唯一key,否则React会出现性能问题和渲染错误。
  • text.split("\n")可能会产生空字符串项(比如文件末尾的换行),建议用filter(Boolean)过滤掉。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:56:20