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

React组件useEffect空依赖时API调用两次问题排查

问题分析

你遇到的情况是开发环境下修改代码热重载后,API请求结果restaurants打印两次,但useEffect内的called仅打印一次,核心原因是热重载时旧组件实例的异步请求未被取消:

  • 首次页面刷新时,组件正常挂载,执行一次useEffect,完成一次请求并打印结果。
  • 修改代码触发热重载时,旧组件实例会被卸载,但它发起的fetch请求可能还未完成;新组件实例挂载后又发起一次新请求,当两个请求都完成时,就会打印两次restaurants,而called因新实例仅执行一次useEffect,所以只打印一次。

另外,React 18开发环境的Strict Mode会触发组件两次挂载/卸载,若未处理请求取消,也可能导致类似重复打印,但结合你描述的called仅打印一次,热重载的影响是主要原因。

解决方案

通过AbortController在组件卸载时取消未完成的请求,避免旧实例的异步操作继续执行:

import { useEffect } from "react";

const ResMenu = () => {
  const fetchData = async (controller) => {
    try {
      const data = await fetch(
        "https://www.swiggy.com/dapi/menu/pl?page-type=REGULAR_MENU&complete-menu=true&lat=28.7040592&lng=77.10249019999999&restaurantId=622616&catalog_qa=undefined&submitAction=ENTER",
        { signal: controller.signal }
      );
      const json = await data.json();
      const restaurants = json?.data?.cards[2]?.groupedCard?.cardGroupMap?.REGULAR?.cards[2]?.card?.card?.itemCards;
      console.log(restaurants);
    } catch (error) {
      // 忽略请求取消导致的错误
      if (error.name !== 'AbortError') {
        console.error('请求失败:', error);
      }
    }
  };

  useEffect(() => {
    const controller = new AbortController();
    console.log("called");
    fetchData(controller);

    // 组件卸载时取消请求
    return () => controller.abort();
  }, []);

  return (
    <div className="res-menu">
      Res Menu
    </div>
  );
};

export default ResMenu;
补充说明
  • 该现象仅出现在开发环境,生产环境无热重载机制,且Strict Mode不会执行两次挂载,不会出现重复打印问题。
  • 保留React Strict Mode有助于提前发现组件副作用问题,不建议为避免此现象关闭它。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 15:18:45