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

React 18自定义useFetch钩子重复执行fetch请求Bug排查

问题根本原因

这是React v18 开发环境下**严格模式(Strict Mode)**的预设行为,不是代码逻辑错误。
React 18 版本起,开发环境开启严格模式时,所有组件首次挂载流程会被刻意执行两次:首次挂载 -> 模拟执行卸载清理逻辑 -> 重新挂载,这个设计的目的是提前检测副作用代码的清理逻辑是否完备,避免上线后出现内存泄漏、残留请求未取消之类的问题。
你观察到的执行流和这个机制完全对应:

  1. 组件首次挂载:useFetch执行,内部useEffect触发,发起第一次fetch请求,打印到Inside the fetch function日志
  2. React触发模拟卸载流程:自动执行useEffect返回的清理函数,也就是controller.abort(),你看到的Fetch aborted日志就来自这一步
  3. 组件重新挂载:useFetch再次执行,useEffect第二次触发,发起第二个fetch请求
  4. 注意:AbortController中断fetch只能阻止前端接收响应后的后续处理,无法终止已经发到服务端的请求,如果服务端已经接收请求开始处理,响应还是会正常返回。等第一个请求的响应返回后,状态更新触发组件重渲染,就会出现你看到的useFetch额外调用一次的现象。

这个双调用行为仅在开发环境生效,生产环境打包后组件只会正常挂载一次,不会出现重复请求的问题。

优化建议
  • 你当前代码里对AbortError的判断逻辑是正确的,捕获到中断错误时不会更新错误状态,不会影响生产环境的正常运行。
  • 不推荐通过移除根组件的<StrictMode>标签规避这个现象,严格模式能在开发阶段提前暴露很多副作用相关的潜在问题,对代码健壮性提升很大。
  • 当前useEffect的空依赖数组存在隐患:你在effect内部用到了url、requestType、headers、body四个外部参数,当这些参数变化时不会自动重新发起请求,建议把这些参数加入依赖数组;对于headers这类对象类型参数,建议用useMemo固定引用,避免不必要的重复请求。
  • 如果不想在开发环境看到冗余的重复请求,也可以直接使用SWR、React Query这类成熟的数据请求库,这类库内部已经做了严格模式下的请求去重、缓存处理,不需要自己手动实现重复请求规避逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 07:51:19