React中useEffect与setInterval实现计时器引发无限渲染问题求助
计时器无限重复渲染问题分析与修复
核心问题原因
1. useEffect未设置依赖数组且未清理定时器
你代码中的两个useEffect都存在致命问题:
- 没有指定依赖数组,导致组件每次渲染都会重新执行useEffect逻辑,重复创建新的定时器,旧定时器未被清除,多个定时器同时触发状态更新,引发频繁渲染循环。
- 缺少定时器清理逻辑,组件卸载或状态变更时,旧定时器仍在后台运行,持续触发状态更新。
2. 定时器闭包捕获旧状态值
Activity.js中定时器的回调直接使用cooldownDuration,由于闭包特性,它捕获的是初始渲染时的状态值,后续每次执行都是用旧值减1000,无法正确更新状态,同时会触发无效的状态更新,加剧渲染循环。
修复方案
1. 修复Activity.js中的useEffect
useEffect(() => { let interval; if (props.activity.cooldown && cooldownDuration > 0) { if (props.activity.id === 1) { console.log('Activity.js state', cooldownDuration); } // 使用函数式更新获取最新状态值 interval = setInterval(() => { setCooldownDuration(prev => prev - 1000); }, 1000); } else { setCooldownDuration(0); } // 清理函数:组件卸载或依赖变更时清除定时器 return () => clearInterval(interval); }, [props.activity.cooldown, cooldownDuration]); // 添加依赖数组,仅在依赖变更时执行
2. 修复ActivityProgression.js中的useEffect
useEffect(() => { const calculatePercentage = () => { const percentage = ((props.totalTime - props.cooldown) / props.totalTime) * 100; setPercentages(percentage); }; calculatePercentage(); // 保留定时器的同时添加清理逻辑 const interval = setInterval(calculatePercentage, 1000); return () => clearInterval(interval); }, [props.totalTime, props.cooldown]); // 添加依赖数组
额外优化建议
进度条的百分比可以直接在渲染时计算,无需用状态存储,减少不必要的状态更新:
return ( <ProgressBar animated now={((props.totalTime - props.cooldown) / props.totalTime) * 100} label={`${Math.round(((props.totalTime - props.cooldown) / props.totalTime) * 100)}%`} /> );
内容的提问来源于stack exchange,提问作者LilyX
相关产品推荐
相关产品推荐

