组件间API数据状态维护问题:页面导航后数据丢失
问题分析与解决方案
可能的触发原因
- 组件重挂载时状态重置:导航离开再返回PokemonPage,组件会重新挂载,
pokemon状态回到初始的undefined,而API请求需要时间,这期间子组件拿到空值,看起来像数据丢失。 - 子组件未处理空值:PokemonCard没针对
pokemon为undefined的情况做兜底,导致数据加载前直接显示异常,误以为数据丢失。 - 请求竞态问题:快速切换页面时,未完成的旧请求可能在组件卸载后仍继续,干扰新请求的状态更新。
修复步骤
1. 给状态设置初始默认结构
避免子组件拿到undefined直接报错,把初始状态改成符合子组件预期的空结构:
const [pokemon, setPokemon] = useState({});
2. 给API请求加取消逻辑
防止组件卸载后请求仍在运行,同时避免请求竞态:
useEffect(() => { const source = axios.CancelToken.source(); const getPokeDetails = async () => { try { const response = await axios.get( `https://pokeapi.co/api/v2/pokemon/${currentPokemon}`, { cancelToken: source.token } ); console.log(`API Data for ${currentPokemon} Loaded`); setPokemon(response.data); } catch (error) { if (!axios.isCancel(error)) { console.error("Failed to fetch pokemon data:", error); } } }; getPokeDetails(); // 组件卸载或参数变化时取消请求 return () => source.cancel("Request canceled"); }, [currentPokemon]);
3. 子组件添加空值判断
在PokemonCard里先判断数据是否存在,没加载完时显示加载状态:
// PokemonCard示例代码 function PokemonCard({ pokemon }) { // 检查数据是否有效 if (!pokemon || !pokemon.name) { return <div>Loading...</div>; } // 正常渲染逻辑 return ( <div> <h3>{pokemon.name}</h3> <img src={pokemon.sprites.front_default} alt={pokemon.name} /> {/* 其他属性渲染 */} </div> ); }
4. 可选:用缓存优化体验(避免重复请求)
如果不想每次返回都重新请求,用React Query这类工具做数据缓存,自动处理状态和请求:
// 先安装react-query:npm install react-query import { useQuery } from "react-query"; function PokemonPage() { const { currentPokemon } = useParams(); const { data: pokemon, isLoading } = useQuery( ["pokemon", currentPokemon], // 缓存键,参数变化时自动重新请求 async () => { const res = await axios.get(`https://pokeapi.co/api/v2/pokemon/${currentPokemon}`); return res.data; } ); return ( <> <h2>{currentPokemon}</h2> {isLoading ? <div>Loading...</div> : <PokemonCard pokemon={pokemon} />} </> ); }
内容的提问来源于stack exchange,提问作者Brandon
相关产品推荐
相关产品推荐

