React useEffect内clearInterval不生效 定时器重复执行问题
预期实现效果
业务需要从API接口获取脚本状态并做判断:
- 当接口返回状态值为
'XYZ'时,通过setInterval定时重复调用getStatus函数轮询状态 - 若状态不为
'XYZ',则直接返回,不执行额外轮询操作
遇到的问题
核心故障为clearInterval清除定时器的逻辑未生效,即使接口返回的状态不等于'XYZ',getStatus函数依然会按照设置的10秒间隔反复被调用。
初始问题代码如下:
const [intervalId, setIntervalId] = useState(); useEffect(() => { getStatus(); }, []); const getStatus = async () => { await getScriptStatus()() .then(response => { if (response.data[0].status == 'XYZ') { setIntervalId( setInterval(() => { getStatus(); }, 10000) ); } else return () => clearInterval(intervalId); }) .catch(error => { errorMessage(error); });
问题根因
用useState存储定时器ID是核心错误:
useState的状态更新是异步的,每次触发状态更新时,闭包里拿到的intervalId永远是上一轮渲染的旧值,根本拿不到最新创建的定时器ID,clearInterval自然无法命中目标定时器- else分支里写的
return () => clearInterval(intervalId)只是在then回调里返回了一个未被任何逻辑接收执行的清理函数,根本不会触发实际清理动作 - 每次进入
XYZ状态分支时没有先清理已存在的旧定时器,会导致多个定时器叠加创建,轮询逻辑会越来越混乱
修复方案
将定时器ID的存储从useState替换为useRef,useRef存储的值在组件全生命周期内保持引用一致,不会因为重渲染拿到过期值;同时每次创建新定时器前先清理已有定时器,避免多定时器叠加,组件卸载时增加兜底清理逻辑防止内存泄漏。
修复后代码参考:
// 用useRef存储定时器ID,保证全生命周期引用一致 const intervalIdRef = useRef(null); useEffect(() => { getStatus(); // 组件卸载时兜底清理定时器 return () => { if (intervalIdRef.current) { clearInterval(intervalIdRef.current); } } }, []); const getStatus = async () => { try { const response = await getScriptStatus()(); if (response.data[0].status === 'XYZ') { // 创建新定时器前先清掉已存在的旧定时器,避免多定时器叠加 if (intervalIdRef.current) { clearInterval(intervalIdRef.current); } intervalIdRef.current = setInterval(() => { getStatus(); }, 10000); } else { // 状态不满足轮询条件,直接清除现有定时器 if (intervalIdRef.current) { clearInterval(intervalIdRef.current); intervalIdRef.current = null; } } } catch (error) { errorMessage(error); } }
问题更新记录:最终通过将intervalId的存储方式从useState替换为React.useRef,同时在if判断分支调用setInterval前先清除已有定时器,问题已成功解决。
内容的提问来源于stack exchange,提问作者Raj Aryan Sharma
相关产品推荐
相关产品推荐

