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
相关产品推荐
相关产品推荐

