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
相关产品推荐
相关产品推荐

