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

在多fetch请求场景下应如何正确放置setCharacters以等待所有请求完成后渲染页面?

问题修复方案

你的代码核心问题是没有正确等待所有嵌套的异步请求完成就调用了状态更新方法,导致页面提前渲染,修复后的完整代码如下:

const api = `https://swapi.dev/api/people/`;
const [characters, setCharacters] = useState([]);
const [fetched, setFetched] = useState(false);

useEffect(() => {
  const fetchAllData = async () => {
    // 拉取人物基础列表
    const baseResponse = await fetch(api);
    const baseData = await baseResponse.json();
    const baseCharacters = baseData.results;

    // 批量拉取每个人物的关联资源,等待全部完成
    const processedCharacters = await Promise.all(
      baseCharacters.map(async (originalCharacter) => {
        // 浅拷贝原始对象,不直接修改源数据
        const character = { ...originalCharacter };
        const { homeworld, species, vehicles, starships } = character;
        // 收集所有需要请求的关联资源地址,过滤空值
        const relationUrls = [homeworld, ...species, ...vehicles, ...starships].filter(Boolean);

        // 拉取当前人物的所有关联资源
        await Promise.all(
          relationUrls.map(async (url) => {
            const res = await fetch(url);
            const data = await res.json();
            if (url.includes("species")) {
              character.species = data.name;
            } else if (url.includes("planets")) {
              character.homeworld = data.name;
            } else if (url.includes("vehicles")) {
              // 匹配对应url替换为名称,适配多载具场景
              character.vehicles = character.vehicles.map(item => item === url ? data.name : item);
            } else if (url.includes("starships")) {
              character.starships = character.starships.map(item => item === url ? data.name : item);
            }
          })
        );

        // 处理空值场景
        if (!character.species.length) character.species = "Unspecified";
        if (!character.vehicles.length) character.vehicles = "";
        if (!character.starships.length) character.starships = "";

        return character;
      })
    );

    // 所有数据全部加载完成后一次性更新状态
    setCharacters(processedCharacters);
    setFetched(true);
  };

  fetchAllData().catch(err => console.error("请求异常:", err));
}, []);

渲染逻辑适配

你只需要在组件渲染时加加载状态判断即可实现全部请求完成后再渲染页面:

// 未加载完成时显示加载提示/动画
if (!fetched) return <div>资源加载中,请稍候...</div>;

// 加载完成后渲染正式内容
return (
  <div>
    {/* 你的人物列表渲染逻辑 */}
    {characters.map(item => <div key={item.name}>{item.name}</div>)}
  </div>
);

主要修改说明

  • 用async/await改写异步逻辑,所有请求的Promise都会被正确收集,外层Promise.all会等待所有资源加载完成后再执行后续操作
  • 所有数据全部加载完成后才会一次性更新状态,不会出现页面先渲染、后刷新的问题
  • 遵循React不可变数据规范,不直接修改请求返回的原始对象,避免异常的状态更新问题
  • 优化了关联资源名称替换逻辑,适配多载具、多星舰的场景,不会出现原代码中shift操作导致的顺序错乱问题

内容的提问来源于stack exchange,提问作者Bartosz Król

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 19:06:03