React调用PokeAPI开发宝可梦图鉴时map渲染元素乱序问题求解
问题原因
- 乱序问题确实和网络/设备性能直接相关:代码中对每只宝可梦的详情请求是并行发起的异步
fetch,没有等待所有请求返回就单个更新listPokemon数组,哪个请求先返回就先把对应数据插入数组末尾,最终数组顺序和请求返回顺序完全一致,和初始的列表顺序无关。手机端网络波动更大、JS线程调度优先级更低,所以乱序出现概率更高。 - 额外隐藏问题:
setLoading(false)写在fetch逻辑外层,会在请求刚发起时就直接关闭加载状态,而非等所有数据加载完成后才关闭。 - 原有代码中包裹
data.results的Promise.all是冗余逻辑,没有实际作用。
修复方案
将单个请求返回就更新数组的逻辑改为等待所有详情请求完成后,按初始顺序统一更新数组即可,Promise.all返回结果的顺序和传入的Promise数组顺序完全一致,不受请求返回先后影响,修改后的getAllPokemon代码如下:
function getAllPokemon(url) { fetch(url) .then((res) => res.json()) .then(async (data) => { // 按原顺序发起所有详情请求,收集Promise const detailPromises = data.results.map((res) => fetch(res.url).then((resp) => resp.json()) ); // 等待所有请求完成,返回顺序和初始data.results顺序完全一致 const allDetails = await Promise.all(detailPromises); // 按原顺序组装新数据 const newPokemonList = data.results.map((res, index) => { const detail = allDetails[index]; return { id: detail.id, name: res.name, url: res.url, image_url: detail.sprites.other["official-artwork"].front_default, }; }); // 统一更新数组 setListPokemon((listPokemon) => [...listPokemon, ...newPokemonList]); // 所有数据加载完成后再关闭loading setLoading(false); }); }
- 若要追求更稳妥的渲染顺序,也可以在渲染前对
listPokemon按id升序排序,修改渲染代码即可:
{listPokemon.sort((a,b) => a.id - b.id).map((p) => ( <Grid> <Card> <CardMedia component="img" image={p.image_url} alt={p.name} /> <CardContent> {p.id}.{setCap(p.name)} </CardContent> </Card> </Grid> ))}
内容的提问来源于stack exchange,提问作者Tuan Le
相关产品推荐
相关产品推荐

