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

React状态未更新:获取新数据后PokemonList组件不刷新

问题原因

你在App组件和PokemonList组件中分别调用了useFetchPokemon,这会创建两个完全独立的Hook实例——它们的状态(pokemon、nextUrl等)是相互隔离的。当你点击App里的按钮更新状态时,修改的只是App组件对应的Hook实例的状态,PokemonList用的是自己那套Hook的状态,自然不会同步更新。

解决方案

只在父组件(App)中调用一次useFetchPokemon,把需要的状态和方法通过props传递给子组件(PokemonList),让两者共享同一套状态。

修改后的代码

1. PokemonList组件(接收props)

import type { FC } from "react";

// 定义props类型,提升类型严谨性
interface PokemonListProps {
  pokemon: {
    name: string;
    sprites: {
      front_default: string;
    };
  }[];
}

const PokemonList: FC<PokemonListProps> = ({ pokemon }) => {
  return (
    <div>
      Pokemon List
      <ul>
        {pokemon.map((p) => (
          <li key={p.name}>
            <img
              alt={p.name}
              style={{ width: "150px", height: "150px", objectFit: "cover" }}
              src={p.sprites.front_default}
            />
            <p>{p.name}</p>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default PokemonList;

2. App组件(传递props)

import PokemonList from './components/PokemonList';
import { useFetchPokemon } from './hooks/useFetchPokemon';

function App() {
  const { pokemon, previousUrl, nextUrl, getNextPokemon, getPreviousPokemon } = useFetchPokemon();
  return (
    <div className="App">
      {previousUrl && <button onClick={getPreviousPokemon}>Previous</button>}
      {nextUrl && <button onClick={getNextPokemon}>Next</button>}
      {/* 将共享的pokemon状态传递给子组件 */}
      <PokemonList pokemon={pokemon} />
    </div>
  );
}

export default App;

可选优化:完善Hook的类型定义

可以去掉useFetchPokemon里的any,让类型更清晰:

import { useState, useEffect } from "react";

interface Pokemon {
  name: string;
  sprites: {
    front_default: string;
  };
}

export const useFetchPokemon = () => {
  const initialUrl = "https://pokeapi.co/api/v2/pokemon"
  const [pokemon, setPokemon] = useState<Pokemon[]>([]);
  const [nextUrl, setNextUrl] = useState<string | null>(null);
  const [previousUrl, setPreviousUrl] = useState<string | null>(null);

  const getPokemonDetails = async (listOfPokemon: { url: string }[]) => {
    const pokemonWithDetails = await Promise.all(
      listOfPokemon.map(async (pokemonItem) => {
        const response = await fetch(pokemonItem.url);
        const data = await response.json() as Pokemon;
        return data;
      })
    );

    return pokemonWithDetails;
  };

  useEffect(() => {
    const getInitalData = async () => {
      const response = await fetch(initialUrl);
      const { results, next, previous } = await response.json();
      const pokemonData = await getPokemonDetails(results);

      setNextUrl(next);
      setPreviousUrl(previous);
      setPokemon(pokemonData);
    };

    getInitalData();
  }, []);

  const getNextPokemon = async () => {
    if(!nextUrl) return;
    const response = await fetch(nextUrl);
    const { results, next, previous } = await response.json();

    const newPokemon = await getPokemonDetails(results);

    setNextUrl(next);
    setPreviousUrl(previous);
    setPokemon(newPokemon);
  };

  const getPreviousPokemon = async () => {
    if(!previousUrl) return;
    const response = await fetch(previousUrl);
    const { results, next, previous } = await response.json();

    const previousPokemon = await getPokemonDetails(results);

    setNextUrl(next);
    setPreviousUrl(previous);
    setPokemon(previousPokemon);
  };

  return { pokemon, nextUrl, previousUrl, getNextPokemon, getPreviousPokemon };
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 06:10:01