React中如何停止setInterval?速打游戏倒计时失效问题
问题原因分析
你的代码里let timer是在组件顶层声明的,组件每次因sec更新而重新渲染时,这个变量都会被重新创建,原来的定时器引用会直接丢失。当sec <= 0时执行clearInterval(timer),操作的其实是一个新的、未赋值的timer变量,自然无法停止之前创建的定时器。另外,直接在组件顶层写if(sec <=0)的逻辑,会在每次组件渲染时都触发,逻辑也不够严谨。
解决方案:用useRef保存定时器引用
React中要用useRef来存储定时器这类需要跨渲染保持引用的值,它的.current属性在组件整个生命周期内都不会随渲染重置。同时配合useEffect监听倒计时状态,双重保障定时器的清理,还能避免组件卸载时的内存泄漏。
修改后的代码如下:
import { useState, useRef, useEffect } from 'react'; const countdownValue = 15; function TypingGameCountdown() { const [sec, setSec] = useState(countdownValue); const timerRef = useRef(null); // 用useRef持久化定时器引用 function start() { // 启动前先清除已有定时器,避免重复创建导致倒计时加速 if (timerRef.current) { clearInterval(timerRef.current); } setSec(countdownValue); // 重置倒计时数值 timerRef.current = setInterval(() => { setSec(prevSec => { // 倒计时即将归0时直接清除定时器 if (prevSec <= 1) { clearInterval(timerRef.current); return 0; } return prevSec - 1; }); }, 1000); } // 监听sec变化,作为清理定时器的额外保障,同时处理组件卸载逻辑 useEffect(() => { if (sec <= 0 && timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; // 清空引用,避免无效调用 } // 组件卸载时强制清除定时器,防止内存泄漏 return () => { if (timerRef.current) { clearInterval(timerRef.current); } }; }, [sec]); return ( <div> <p>剩余时间:{sec}秒</p> <button onClick={start}>开始游戏</button> </div> ); } export default TypingGameCountdown;
关键说明
- useRef存储定时器:确保组件多次渲染后,始终能拿到同一个定时器的引用,不会丢失。
- 启动前清理旧定时器:避免用户多次点击启动按钮创建多个定时器,导致倒计时速度异常。
- setSec内部判断清理:在更新倒计时数值的同时直接处理归0逻辑,减少额外的状态监听开销。
- useEffect兜底清理:既监听倒计时状态做保障,又在组件卸载时清理定时器,彻底避免内存泄漏。
内容的提问来源于stack exchange,提问作者user18243088
相关产品推荐
相关产品推荐

