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

ReactJS抽离数据获取逻辑后如何编写useEffect清理函数

useEffect抽离请求函数后的清理逻辑实现

你当前代码的问题

你现在写的清理逻辑是完全无效的:mountedTodos变量定义在useEffect的回调作用域里,抽离出去的getTodos函数根本访问不到这个变量,哪怕组件卸载时你把mountedTodos设为false,getTodos里的逻辑完全感知不到,等请求返回后依然会执行setTodos,还是会触发React的内存泄漏警告。

推荐实现方案

方案1:使用原生AbortController(最优解)

这个方案不仅能避免卸载后更新状态,还能直接中断未完成的网络请求,比单纯的挂载标记更合理,抽离的请求函数也能保持很好的复用性:

// 抽离的请求函数接收AbortSignal作为入参,只负责数据获取,不耦合组件状态
const getTodos = async (signal) => {        
  try {
    // 将signal传入fetch配置,中断请求时会自动抛出AbortError
    const response = await fetch('https://jsonplaceholder.typicode.com/todos/1', { signal });
    return await response.json();
  } catch(e) {
    // 主动中断的请求不需要打印错误
    if (e.name !== 'AbortError') {
      console.log(e);
    }
    return null;
  }
}    

useEffect(() => {
  const controller = new AbortController();
  // 调用请求时传入控制信号
  getTodos(controller.signal).then(todos => {
    if (todos) {
      setTodos(todos);
    }
  });

  return () => {
    // 组件卸载时直接中断请求
    controller.abort();
  };
}, []);

这个方案的优势:

  • 真正中断未完成的网络请求,节省流量
  • 请求函数和组件状态解耦,可直接复用到其他组件
  • 不需要依赖闭包变量做判断,逻辑更清晰

方案2:拆分职责,把状态更新逻辑留在useEffect作用域

如果你不想引入AbortController,只要调整抽离逻辑的边界就行:抽离的函数只负责纯数据请求,所有和组件状态相关的setState操作,全部放回useEffect内部执行,这样就能和你最开始写的内联请求逻辑一样,正常访问挂载标记:

// 抽离纯请求逻辑,不做任何状态更新
const getTodos = async () => {        
  const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
  return response.json();
}    

useEffect(() => {
  let isMounted = true;

  getTodos()
    .then(todos => {
      // 这里能正常访问到isMounted标记
      if (isMounted && todos) {
        setTodos(todos);
      }
    })
    .catch(e => console.log(e));

  return () => {
    isMounted = false;
  };
}, []);

常见踩坑提醒

  • 不要给async函数传普通布尔类型的挂载标记:基础类型是值传递,函数内部拿到的永远是调用那一刻的true,根本感知不到后续标记变为false的变化,判断完全失效。
  • 不要给useEffect的回调函数加async关键字:async函数默认返回Promise,React无法识别你return的清理函数,会导致清理逻辑直接失效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 20:48:20