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

React Native中useEffect的正确用法及组件卸载状态更新警告修复

React Native useEffect内存泄漏警告解决方案

问题根源

你当前只取消了InteractionManager的调度任务,但调度执行后发起的4个fetch异步请求没有被终止,请求响应后仍然会执行setState操作,如果此时组件已经卸载,就会触发该警告。另外你原useEffect存在两个低级问题:一是读取task的闭包陷阱,清理函数拿到的task永远是初始值null,cancel方法根本没生效;二是清理函数的括号位置存在语法错误,导致清理逻辑本身就没有正常注册。

修复步骤

    1. 重构useEffect逻辑,新增挂载标记和请求取消控制器,规避闭包问题
useEffect( () => {
  let isMounted = true; // 组件挂载状态标记
  let interactionTask = null;
  const abortController = new AbortController(); // fetch请求取消控制器

  const fetchData = async () => {
    interactionTask = InteractionManager.runAfterInteractions( async () => {
      try {
        const _token =  await AsyncStorage.getItem('@token');
        const UserId = await AsyncStorage.getItem('@UserID')
        // 组件已卸载则直接终止后续逻辑
        if(!isMounted) return;
        setToken(_token);
        
        // 并行发起请求,传入取消信号和挂载标记
        await Promise.all([
          fetchParents(UserId, _token, abortController.signal, isMounted),
          fetchStudent(UserId, _token, abortController.signal, isMounted),
          fetchTeacher(UserId, _token, abortController.signal, isMounted),
          UserProfile(UserId, _token, abortController.signal, isMounted)
        ])
      } catch(e) {
        // 忽略请求取消抛出的错误
        if(e.name !== 'AbortError') {
          console.log(e);
        }
      }
    });
  }

  fetchData()

  // 组件卸载时执行清理
  return () => {
    isMounted = false; // 标记组件已卸载
    interactionTask?.cancel(); // 取消InteractionManager调度任务
    abortController.abort(); // 终止所有未完成的fetch请求
  };
}, [])
    1. 改造fetch类函数,支持取消控制和挂载状态判断,以fetchParents为例:
const fetchParents = async (UserId, _token, signal, isMounted) => {
  try {
    const response = await fetch(config.API_URL + '/Parents/Application/Access/10/'+UserId, {
      method: 'GET',
      headers: {
        'Authorization': 'Bearer '+ _token,
        'Content-Type': 'application/json',
      },
      signal // 绑定取消信号
    })
    const data = await response.json();
    // 仅组件未卸载、请求成功时才更新状态
    if(isMounted && response.status === 200) {
      if(data.length > 0) {
        setParent(data[0].udf_Users_IsHaveApplicationAccess)
      } else {
        console.log("err");
      }
    }
  } catch (e) {
    if(e.name !== 'AbortError') {
      console.log(e);
    }
  }
}

其余fetchStudent/fetchTeacher/UserProfile函数参照fetchParents的逻辑改造即可。

核心注意点

  • 挂载标记判断:所有setState操作前都要校验组件是否还处于挂载状态,避免卸载后更新状态触发警告
  • AbortController使用:fetch原生支持的取消机制,组件卸载时主动终止未完成的请求,既避免无用回调,也节省网络资源
  • 不要在useEffect外部定义依赖useEffect作用域变量的异步逻辑,规避闭包陷阱导致的清理失效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 22:36:05