React重渲染时setInterval工作机制及未用useRef失效原因
React组件重渲染时setInterval的工作机制解析
问题场景
开发React倒计时应用时遇到了一个问题:直接用let startTimer存储定时器ID时,调用clearInterval无法停止定时器;改用useRef后就能正常暂停。
为什么不用useRef时定时器停不下来?
React组件的核心特性是:每次状态更新(比如调用setIsCounting)都会重新执行整个组件函数。
看你最初的代码:
let startTimer; const onStart = () => { startTimer = setInterval(()=>{ if (timeRemaining === 0) { clearInterval(startTimer); setIsCounting(false) return } updateTimer() }, 1000) setIsCounting(prev => !prev) } const onPause = () => { setIsCounting(prev => !prev) clearInterval(startTimer) }
- 点击Start按钮,
onStart执行:给startTimer赋值了定时器ID,随后调用setIsCounting触发组件重渲染。 - 重渲染时,组件函数重新执行,会重新声明一个全新的
startTimer变量(值为undefined),和之前存储定时器ID的变量完全不是同一个引用。 - 点击Pause按钮时,
onPause里的startTimer是这个新的undefined,调用clearInterval(undefined)根本无法终止之前创建的定时器,所以定时器会继续运行。
useRef为什么能解决问题?
useRef是React提供的用于保存跨重渲染持久化值的Hook,它创建的对象在组件的整个生命周期内是同一个引用,不会因为组件重渲染而被重新创建。
看修改后的代码:
const startTimer = useRef(null) const onStart = () => { startTimer.current = setInterval(()=>{ if (timeRemaining === 0) { clearInterval(startTimer.current); setIsCounting(false) return } updateTimer() }, 1000) setIsCounting(prev => !prev) } const onPause = () => { setIsCounting(prev => !prev) clearInterval(startTimer.current) }
startTimer.current存储的定时器ID,不管组件重渲染多少次,始终指向同一个值。- 点击Pause时,
onPause能拿到正确的定时器ID,调用clearInterval(startTimer.current)就能成功终止定时器。
内容的提问来源于stack exchange,提问作者Jasper
相关产品推荐
相关产品推荐

