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

React Hooks:如何等待所有API数据获取完成后再执行setState?

你的问题核心是forEach里的异步回调不会等待Promise完成,循环刚执行完就立刻调用了setTableData,这时候getUserItemName的请求还处于pending状态,item.name根本没赋值,所以表格拿到的是不完整数据。

解决方法

1. 用Promise.all等待所有子请求完成

把遍历数据的forEach改成map,收集每个异步请求的Promise,再用Promise.all等待全部请求完成后再更新表格状态。同时统一用await语法,避免混用await和then导致逻辑混乱。

修改后的getInitialData代码:

const getInitialData = async () => {
  const username = user.username;
  // 先获取主数据
  const mainResponse = await axios.get(`http://localhost:8080/api/sellers/${username}/someData`);
  const data = mainResponse.data;

  // 遍历每个item,发起子请求并等待全部完成
  await Promise.all(data.map(async (item) => {
    item.name = await getUserItemName(username, item.id);
  }));

  // 所有数据补全后,再更新表格状态
  setTableData(data);
};

2. 可选:添加加载状态优化体验

可以新增一个isLoading状态,在数据加载完成前显示加载提示,避免表格空显示或展示不完整内容:

const [isLoading, setIsLoading] = useState(true);
const [tableData, setTableData] = useState([]);

const getInitialData = async () => {
  setIsLoading(true);
  const username = user.username;
  try {
    const mainResponse = await axios.get(`http://localhost:8080/api/sellers/${username}/someData`);
    const data = mainResponse.data;
    await Promise.all(data.map(async (item) => {
      item.name = await getUserItemName(username, item.id);
    }));
    setTableData(data);
  } catch (error) {
    console.error('数据加载失败:', error);
    // 这里可以加用户提示,比如alert('加载失败,请重试')
  } finally {
    setIsLoading(false);
  }
};

对应的表格组件修改为:

{isLoading ? <div>加载中...</div> : <SortingTable ref={sortingTableRef} columns={TABLE_COLUMNS} data={tableData}/>}

原代码问题解析

forEach不会处理异步函数的返回值,哪怕你在回调里写了await,forEach也会直接跳过等待,继续执行下一次循环。所以循环结束时,所有getUserItemName的请求还在后台运行,此时setTableData传入的是还没补全name的原始数据,导致表格提前渲染。

而map会把每个异步回调的Promise收集成数组,Promise.all会等待数组中所有Promise都成功resolve后,才继续执行后续代码,确保所有item.name都赋值完成后再更新表格状态。

内容的提问来源于stack exchange,提问作者CK2002

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 19:47:16