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

React使用useEffect+Promise请求API时响应重复打印两次问题

接口响应重复打印2次问题排查与修复

核心原因

  • 你使用的是React 18+版本,且项目入口默认开启了React.StrictMode严格模式。该模式在开发环境下会主动执行两次组件挂载、卸载流程,用来提前检测组件副作用的不规范写法:组件首次挂载时useEffect执行一次、触发第一次请求,紧接着组件会被卸载重挂,useEffect再执行一次、触发第二次请求,因此console.log会打印两次接口结果。该行为仅在开发环境存在,生产环境打包后不会重复执行,不影响线上逻辑。
  • 代码中存在潜在的重复触发风险:你在getData函数刚拼接完请求地址就执行setdesireCountry("")修改state,如果后续给useEffect添加了相关依赖,会直接触发effect重跑、多发起一次请求。
  • 搜索按钮直接绑定getData作为点击事件,若存在事件冒泡、误触发场景也会额外发起请求,但这不是你当前遇到两次打印的核心诱因。

修复方案

  • 不推荐的快速方案:直接删除入口文件(通常是src/index.js)中包裹App组件的<React.StrictMode>标签,即可关闭开发环境的双重执行逻辑。但严格模式可以提前帮你发现副作用未清理、生命周期写法不安全等问题,直接关闭会损失开发校验能力。
  • 推荐的规范修复方案:给请求加中断清理逻辑,适配严格模式的执行逻辑,同时调整不合理的state更新时机,参考修改如下:
// 调整covidData初始值为空对象,避免首次渲染解构空字符串导致的属性访问异常
const [covidData, setcovidData] = useState({});
const [desireCountry, setdesireCountry] = useState("pakistan");

useEffect(() => {
  // 初始化请求中断控制器
  const abortController = new AbortController();
  const getData = async () => {
    try {
      const url = `https://covid-19.dataflowkit.com/v1/${desireCountry}`;
      const covidData = await fetch(url, {
        signal: abortController.signal // 绑定中断信号
      });
      const featchedData = await covidData.json();
      console.log(featchedData);
      // 原有对象解构逻辑保持不变
      const {
        Country_text,
        ["Last Update"]: lastUpdate,
        ["Total Cases_text"]: totalCases,
        ["Total Deaths_text"]: deathCases,
        ["Total Recovered_text"]: recoverCases,
        ["New Deaths_text"]: newDeaths,
        ["Active Cases_text"]: activeCases,
        ["New Cases_text"]: newCases,
        ["Total Deaths_text"]: totalDeaths,
      } = featchedData;

      if (Country_text === "World") {
        alert("Country name not correct.please Enter a correct country name");
      } else {
        const coronaData = {
          Country_text,
          lastUpdate,
          totalCases,
          deathCases,
          recoverCases,
          newDeaths,
          activeCases,
          newCases,
          totalDeaths,
        };
        setcovidData(coronaData);
        // 请求成功后再清空输入框,避免请求过程中修改state触发额外重渲染
        setdesireCountry("");
      }
    }
    catch(err) {
      // 主动中断的请求不弹出错误提示
      if (err.name !== 'AbortError') {
        alert(`server not responding`)
      }
    }
  };
  getData();
  // 组件卸载/重跑effect前中断未完成的旧请求,避免竞态问题
  return () => {
    abortController.abort();
  }
}, []);

额外提示:你代码里重复解构了Total Deaths_text字段,属于冗余代码,可以删掉重复的声明。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 20:24:10