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

React18中useEffect重复执行、useCallback无效如何解决

问题原因

React 18 版本中,开发环境下的<React.StrictMode>默认开启了组件首次挂载的重挂载检查:为了提前定位effect缺少清理逻辑导致的潜在问题,会自动执行「组件挂载 -> 模拟卸载 -> 组件重新挂载」的流程,因此没有配置清理函数的useEffect会被连续执行两次。
这个行为仅在开发环境生效,生产环境构建后不会触发重复挂载逻辑,useEffect只会正常执行一次。该问题和你是否使用useCallback包裹请求方法无关,useCallback本身也无法阻止Strict Mode下的effect重执行。

可行解决方案

方案1:为请求增加取消逻辑(官方推荐)

这是最符合React设计思路的方案,既可以解决开发环境重复请求的问题,也能避免组件卸载后请求仍在运行导致的内存泄漏、状态更新报错问题,生产环境同样适用。核心实现是借助AbortController在effect的清理函数中取消上一次未完成的请求,修改后的代码如下:

import { useEffect, useCallback } from "react";

function App() {
  const fetchUsers = useCallback(async (signal) => {
    try {
      const response = await fetch(
        "https://jsonplaceholder.typicode.com/users",
        { signal }
      );
      const data = await response.json();
      console.log("data: ", data);
    } catch (error) {
      // 过滤主动取消请求抛出的异常
      if (error.name !== "AbortError") {
        console.log("Error in catch!", error);
      }
    }
  }, []);

  useEffect(() => {
    const abortController = new AbortController();
    fetchUsers(abortController.signal);
    // effect重执行/组件卸载前,取消上一次未完成的请求
    return () => abortController.abort();
  }, [fetchUsers]);
}

export default App;

该方案下第一次挂载触发的请求会在重挂载流程中被主动取消,只有第二次发起的请求会正常返回并处理结果,不会出现控制台重复打印数据的问题。

方案2:开发环境增加单次执行标记

如果你的请求逻辑暂时无法接入取消能力,可以借助useRef做开发环境下的执行标记,拦截重复的请求调用。注意不要依赖该标记实现业务幂等,它仅用于兼容开发环境的Strict Mode检查,生产环境下组件不会触发重挂载流程,该标记不会影响正常的请求发起逻辑:

import { useEffect, useCallback, useRef } from "react";

function App() {
  // 标记请求是否已经发起过
  const hasFetchedRef = useRef(false);

  const fetchUsers = useCallback(async () => {
    try {
      const response = await fetch(
        "https://jsonplaceholder.typicode.com/users"
      );
      const data = await response.json();
      console.log("data: ", data);
    } catch (error) {
      console.log("Error in catch!");
    }
  }, []);

  useEffect(() => {
    if (hasFetchedRef.current) return;
    hasFetchedRef.current = true;
    fetchUsers();
  }, [fetchUsers]);
}

export default App;
注意事项

不建议通过移除<React.StrictMode>的方式规避问题。Strict Mode触发的重复执行本质是提前暴露代码隐患:如果你的effect没有写清理逻辑,实际生产环境中组件正常的重挂载、路由跳转场景下,一样会出现重复请求、内存泄漏、重复事件绑定等问题,Strict Mode只是把这些问题提前在开发阶段暴露出来,降低线上故障概率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 11:18:16