React倒计时定时器打印值始终为10无法触发清零逻辑如何解决?
问题根因
- 闭包陷阱:
counter函数在组件首次渲染时创建,捕获了初始状态time=10,后续组件重渲染生成的新counter函数不会被已经启动的定时器调用,所以每次执行定时器回调拿到的永远是初始的10,永远进不了else分支 - 定时器ID未正确存储:原代码中没有存储
setInterval的返回值,clearInterval调用时的timer变量属于未定义,就算满足终止条件也清不掉定时器 - 普通变量
flag无法跨渲染周期持久化:每次组件重渲染都会重置flag = true,没有起到防止重复启动定时器的作用
修复方案
修改后的完整JS代码如下:
const {useState, useRef, useEffect} = React; const Timer = () => { const [time, setTime] = useState(10); // 用useRef存储定时器ID,跨渲染周期保持引用 const timerRef = useRef(null); // 标记定时器是否已经启动,防止重复点击开启多个定时器 const isStartedRef = useRef(false); const counter = () => { setTime(prevTime => { console.log(prevTime); if (prevTime <= 1) { // 倒计时到0时清除定时器 clearInterval(timerRef.current); isStartedRef.current = false; console.log('out'); return 0; } return prevTime - 1; }) } const handleClick = () => { if (!isStartedRef.current) { isStartedRef.current = true; timerRef.current = setInterval(counter, 500); } } // 组件卸载时清除定时器,避免内存泄漏 useEffect(() => { return () => { if (timerRef.current) { clearInterval(timerRef.current); } } }, []) return( <div> <div>{time}</div> <button className="start" onClick={handleClick}>START</button> </div> ) } ReactDOM.render( <Timer />, document.getElementById("react") );
HTML代码无需修改。
修改点说明
- 引入
useRef存储定时器ID和启动状态,确保值不会因为组件重渲染被重置 - 将倒计时判断逻辑放到
setTime的更新回调中,直接取上一次的最新状态值,避开闭包陷阱 - 增加组件卸载时清理定时器的逻辑,避免组件销毁后定时器还在运行导致内存泄漏
- 修复了未定义
timer变量的问题,所有定时器操作都通过timerRef.current调用
内容的提问来源于stack exchange,提问作者dorota
相关产品推荐
相关产品推荐

