React Native中useEffect的正确用法及组件卸载状态更新警告修复
React Native useEffect内存泄漏警告解决方案
问题根源
你当前只取消了InteractionManager的调度任务,但调度执行后发起的4个fetch异步请求没有被终止,请求响应后仍然会执行setState操作,如果此时组件已经卸载,就会触发该警告。另外你原useEffect存在两个低级问题:一是读取task的闭包陷阱,清理函数拿到的task永远是初始值null,cancel方法根本没生效;二是清理函数的括号位置存在语法错误,导致清理逻辑本身就没有正常注册。
修复步骤
- 重构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请求 }; }, [])
- 改造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
相关产品推荐
相关产品推荐

