解决React Native中useEffect引发的setInterval无限循环问题
问题分析
你的代码出现无限循环卡顿的核心原因有两个:
- 定时器频繁重建:
useEffect的依赖项是location,如果location是实时更新的定位数据(比如每秒刷新),每次location变化都会销毁旧定时器并创建新定时器,短时间内大量的定时器创建/销毁操作直接导致Android应用卡顿。 - 闭包状态引用问题:
sendCoordinate内部直接引用外部的location状态,而非优先使用传入的参数,加上函数未做缓存,容易出现状态引用过期或不必要的重复执行。
修复方案
1. 稳定定时器,避免频繁重建
用useRef保存最新的location和定时器实例,将useEffect的依赖改为空数组,仅在组件挂载时创建一次定时器:
import { useEffect, useRef } from 'react'; // 保存最新location,避免闭包捕获旧值 const locationRef = useRef(location); useEffect(() => { locationRef.current = location; }, [location]); // 仅挂载时创建一次定时器 useEffect(() => { const interval = setInterval(() => { sendCoordinate(locationRef.current); }, 180000); // 3分钟间隔 return () => clearInterval(interval); }, []);
2. 缓存发送函数,修正状态引用逻辑
用useCallback包裹sendCoordinate,确保函数引用稳定,同时优先使用传入的位置参数,避免闭包问题:
const sendCoordinate = useCallback(async (locParms) => { console.log("@2 it working3", checkDayStatus, locParms); if (checkDayStatus !== "Started") return; const targetLoc = locParms || locationRef.current; if (!targetLoc) return; // 无有效位置数据时直接返回 const data = { lat: targetLoc.lat, lng: targetLoc.lng, dispatcher_id: 1, truck_id: 1, }; return await LocationAPI.sendLocationFeed(data); }, [checkDayStatus]);
3. 额外优化:防止异步请求叠加
如果接口请求耗时意外超过3分钟,可加请求锁避免并发请求堆积:
const isRequesting = useRef(false); const sendCoordinate = useCallback(async (locParms) => { if (isRequesting.current) return; // 已有请求在执行时直接跳过 if (checkDayStatus !== "Started") return; const targetLoc = locParms || locationRef.current; if (!targetLoc) return; isRequesting.current = true; try { const data = { lat: targetLoc.lat, lng: targetLoc.lng, dispatcher_id: 1, truck_id: 1, }; await LocationAPI.sendLocationFeed(data); } catch (err) { console.error("发送位置失败:", err); } finally { isRequesting.current = false; } }, [checkDayStatus]);
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

