React倒计时计时器因重渲染跳过数字(10直接到8)求助
解决React倒计时跳过数字9的问题
问题原因
你的代码问题在于每次time更新都会触发useEffect创建新的定时器,再加上React开发环境的Strict Mode会双重调用useEffect,导致初始阶段同时存在两个定时器:
- 第一个定时器在1秒后把
10减到9 - 第二个定时器几乎同时执行,把刚更新的
9立刻减到8
所以页面上直接从10跳到8,跳过了9。
修复方案
有两种可靠的修复方式:
方式1:清理定时器+限制仅在倒计时未结束时创建定时器
给useEffect添加清理函数,避免残留定时器;同时只在time > 0时创建新的定时器:
import React, { useState, useEffect } from 'react' import "./App.css"; export default function App() { const [time, setTime] = useState(10); useEffect(() => { // 只有倒计时未结束时才创建定时器 if (time <= 0) return; const timer = setTimeout(() => { setTime(a => a - 1); }, 1000); // 清理函数:组件卸载或依赖更新时清除定时器 return () => clearTimeout(timer); }, [time]); return ( <div className="container"> <h1>Countdown</h1> { time <= 0 ? <p>Time's Up!</p> : <p>{time}</p> } </div> ) }
方式2:使用setInterval替代setTimeout
如果是倒计时场景,setInterval更适合,因为它只需要创建一次定时任务,每隔1秒执行一次:
import React, { useState, useEffect } from 'react' import "./App.css"; export default function App() { const [time, setTime] = useState(10); useEffect(() => { const timer = setInterval(() => { setTime(prev => { // 倒计时结束时清除定时器 if (prev <= 1) { clearInterval(timer); return 0; } return prev - 1; }); }, 1000); // 组件卸载时清除定时器 return () => clearInterval(timer); }, []); // 依赖为空数组,仅在组件挂载时执行一次 return ( <div className="container"> <h1>Countdown</h1> { time <= 0 ? <p>Time's Up!</p> : <p>{time}</p> } </div> ) }
说明
两种方案都能解决跳过数字的问题:
- 方式1保留了
setTimeout的逻辑,通过清理函数避免多个定时器冲突 - 方式2用
setInterval更贴合倒计时的场景,减少不必要的useEffect触发
内容的提问来源于stack exchange,提问作者Larry-Larriee
相关产品推荐
相关产品推荐

