使用Poke API获取初代宝可梦数据出现重复元素的解决咨询
解决Poke API获取初代宝可梦重复元素及map报错问题
问题分析
重复元素原因:
- 当前代码在每个宝可梦请求返回后,就调用
setAllPokemons往数组里添加单条数据,若useEffect被多次触发(比如依赖数组写了无意义的[0]、开发环境热重载),会导致多次发起全量请求,数组重复插入相同元素。 - 并行异步请求的状态更新也可能因时机问题引发重复(虽函数式更新能缓解,但批量处理更稳妥)。
- 当前代码在每个宝可梦请求返回后,就调用
修改后报错原因:
- 把
setAllPokemons((urls) => [...urls, res.data])改成直接赋值setAllPokemons(res.data),会将allPokemons从数组覆盖成单个宝可梦对象,后续调用allPokemons.map时自然报错——对象没有map方法。
- 把
解决方案
方案一:批量请求后统一更新状态(推荐)
用Promise.all等待所有宝可梦请求完成,一次性把所有数据存入状态,避免多次更新导致的重复,同时确保useEffect只执行一次:
import React from "react"; import Card from "./Card"; import axios from "axios"; export default function Main() { const [allPokemons, setAllPokemons] = React.useState([]); React.useEffect(() => { axios.get("https://pokeapi.co/api/v2/pokemon?limit=151") .then((res) => { const pokeUrls = res.data.results.map((pokemon) => pokemon.url); // 批量发起所有请求,等待全部完成 return Promise.all(pokeUrls.map(url => axios.get(url))); }) .then((responses) => { // 提取所有响应的宝可梦数据 const pokemonList = responses.map(res => res.data); setAllPokemons(pokemonList); }) .catch(err => console.error("请求失败:", err)); }, []); // 空依赖数组,确保组件仅挂载时执行一次请求 const pokemonCard = allPokemons.map((pokemon) => ( <Card name={pokemon.name} key={pokemon.id} id={pokemon.id} img={pokemon.sprites.front_default} type={pokemon.types[0].type.name} /> )); return <div className="main-container">{pokemonCard}</div>; }
方案二:逐步加载时添加去重逻辑
如果需要实现逐步加载(比如每加载一只就显示一只),可以在更新状态时检查是否已存在该宝可梦,避免重复:
// 替换原useEffect内的请求逻辑 axios.get("https://pokeapi.co/api/v2/pokemon?limit=151").then((res) => { const pokeUrls = res.data.results.map((pokemon) => pokemon.url); pokeUrls.map((url) => axios.get(url).then((res) => { setAllPokemons((prevList) => { // 检查当前数组是否已有该id的宝可梦,没有才添加 if (!prevList.some(poke => poke.id === res.data.id)) { return [...prevList, res.data]; } return prevList; // 已存在则返回原数组 }); }) ); });
同时记得把useEffect的依赖数组改成[],避免重复发起请求。
内容的提问来源于stack exchange,提问作者Discoo J
相关产品推荐
相关产品推荐

