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

Next.js/React多层嵌套fetch拉取数据map渲染部分数据不显示

问题根因
  • 循环发起子项数据请求时,每拿到一个接口返回就直接调用setEvaluationResults更新状态,React状态更新为异步执行,后一次更新会直接覆盖前一次的内容,最终状态里只会保留最后一个返回请求的数据,前面拉取的内容会全部丢失。
  • 当前evaluationResults为单值存储结构,没有和evaluationOptions的subTitle做绑定映射,就算所有数据都成功返回,渲染时也无法将内容精准匹配到对应的标题块下,很容易出现串位、内容缺失的问题。
  • 循环内的fetch为并行发起,接口返回顺序不固定,如果用数组按返回顺序存储数据,会出现A标题下渲染B内容的错位问题。
  • 三层fetch嵌套的回调地狱写法没有统一错误捕获,任意一个接口报错都会导致后续逻辑全部中断,且问题定位难度高。
修复方案
  1. 调整状态初始值:将evaluationResults的初始值设为空对象{},用于存储「subTitle -> 对应内容」的映射关系,查找效率高且不会出现内容错位。
  2. 替换循环内单次更新状态的逻辑:使用Promise.all等待所有子项接口全部返回,将所有结果按subTitle组装为完整的映射对象后,再一次性调用setEvaluationResults更新状态,从根源避免状态被反复覆盖的问题。
  3. 渲染层做匹配关联:遍历evaluationOptions时,直接用当前项的subTitle从映射对象中取对应内容渲染,同时增加简单的加载判断,避免数据未返回时读取属性抛出错误。
  4. 推荐使用async/await改写嵌套的then链,代码可读性更高,也方便统一添加错误处理。

修正后的数据拉取代码

const fetchAllEvaluationData = async () => {
  const evaluationId = localStorage.getItem("1317");
  try {
    // 规则1:拉取评估基础信息
    const evalBaseRes = await fetch(`http://localhost:4000/api/evaluations/search-by-id/${evaluationId}`);
    const evaluationDetails = await evalBaseRes.json();
    setEvaluationData(evaluationDetails);

    // 规则2:拉取模板关联的subTitle列表
    const optionRes = await fetch(`http://localhost:4000/api/options/get-all-option-by-title`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${AccessToken}`
      },
      body: JSON.stringify({ title: evaluationDetails.template })
    });
    const subTitleList = await optionRes.json();
    setEvaluationOptions(subTitleList);

    // 规则3:并行拉取所有subTitle对应的内容,全部返回后再统一更新状态
    const resultMap = {};
    await Promise.all(
      subTitleList.map(async (currentOption) => {
        const subDataRes = await fetch(`http://localhost:4000/api/evaluations-data/search-by-id-and-title`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${AccessToken}`
          },
          body: JSON.stringify({
            evaluationId: evaluationId,
            title: currentOption.subTitle
          })
        });
        const subContent = await subDataRes.json();
        // 用subTitle作为key存储对应内容,从结构上避免错位
        resultMap[currentOption.subTitle] = subContent;
      })
    );
    setEvaluationResults(resultMap);
  } catch (err) {
    console.error("评估数据拉取失败:", err);
    // 这里可以加自己的错误提示逻辑,比如弹toast
  }
}

// 在页面加载、evaluationId变化的时机调用该方法即可
fetchAllEvaluationData();

修正后的渲染代码

{
  evaluationOptions.map((evalOptData) => {
    const currentContent = evaluationResults[evalOptData.subTitle];
    return (
      <>
        <b className="px-1 text-light bg-danger">{evalOptData.subTitle}</b>
        <Card.Body>
          <Row className="px-5">
            {currentContent ? 
              // 这里替换成你自己的内容渲染逻辑,根据接口返回的字段调整
              <div>{currentContent.detail}</div> 
              : 
              "内容加载中..."
            }
          </Row>
        </Card.Body>
      </>
    )
  })
}

内容的提问来源于stack exchange,提问作者Mark Willow Aldave

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 17:21:10