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

React Native 提示useEffect未清理订阅与异步任务问题求助

问题1:代码存在的问题

你遇到的报错是由以下几个未正确处理的清理逻辑导致的:

  • 导航监听器依赖错误:你在beforeRemove监听器中使用的是isDoneRef.current(ref值),但useEffect依赖数组中传入的是isDone(状态值)。如果你仅使用ref做判断,不需要将状态加入依赖数组,否则isDone每次变更都会重复销毁、重建监听器,容易出现边界case下的监听泄漏。
  • 单次定位请求未取消:getLocation中调用的Geolocation.getCurrentPosition是异步请求,你没有对应的取消逻辑。如果组件在请求返回前卸载,回调中的setStartPosition会触发已卸载组件的状态更新,直接导致报错。
  • 异步定位监听的竞态问题:getLocationUpdates是异步函数,内部存在await hasLocationPermission、await startForegroundService两个等待逻辑。如果组件在等待过程中卸载,清理函数会先执行,此时currentPositionRef还未被赋值,clearWatch逻辑不会触发。等待结束后才会执行Geolocation.watchPosition赋值给currentPositionRef,这个监听就永远不会被清理,后续回调触发setCurrentPosition就会报错。
  • 卸载后执行状态更新:第三个定时器useEffect的清理函数中写了setTimer(0),组件卸载时清理函数执行,此时调用setTimer会直接触发已卸载组件的状态更新,属于典型的泄漏报错场景。
问题2:精准定位未清理函数的方法
  • 给每个useEffect的回调、清理函数加唯一标识的console.log,同时给所有异步回调(比如定位的成功/失败回调、定时器回调)加上标识日志,报错前最后打印的日志对应的函数就是泄漏的来源。
  • 新增一个isMountedRef引用:在组件顶层声明const isMountedRef = useRef(false),在所有useEffect的回调开头将isMountedRef.current = true,清理函数中将isMountedRef.current = false。在所有setState调用前先判断isMountedRef.current是否为true,若为false则打印当前回调的标识,即可直接定位到泄漏的异步逻辑。
  • 开启React严格模式(StrictMode),此时开发环境下组件会执行「挂载-卸载-重新挂载」的流程,会放大泄漏问题,更容易快速复现定位。
  • 可以在每个setState调用前打堆栈日志:console.trace('触发状态更新'),就能直接看到是哪个函数触发了卸载后的状态更新。

内容的提问来源于stack exchange,提问作者Bagus Amrullah Fikri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 07:24:04