使用Moment.js实现2分钟倒计时时计时器停在1:59无法递减问题求助
问题原因
- useEffect中定义的
duration是固定常量,值恒为初始2分钟对应的毫秒数。setInterval回调每次执行时,都是用这个固定值减1000,得到的结果永远是119000毫秒(对应1分59秒),更新到state后不会再变化,所以计时器卡住。 - duration state初始化值为null,首次调用
getFinalTime时入参为空可能引发异常。 - 原有逻辑计算的初始duration永远是2分钟,没有考虑组件加载时已经过去的时间,不符合真实倒计时场景需求。
修复后代码
import { useState, useCallback, useEffect } from 'react'; import moment from 'moment'; // 注意billData如果是外部传入的参数,需要补到组件入参里 const CountDownTimer = ({ billData }) => { // 初始值设为0避免空值异常 const [duration, setDuration] = useState(0); const getFinalTime = useCallback((duration) => { const currentDuration = moment.duration(duration, "milliseconds"); let finalMinutes = currentDuration.minutes(); let finalSeconds = currentDuration.seconds(); finalMinutes = finalMinutes < 10 ? `0${finalMinutes}` : finalMinutes; finalSeconds = finalSeconds < 10 ? `0${finalSeconds}` : finalSeconds; return `${finalMinutes}:${finalSeconds}`; }, []); useEffect(() => { if (!billData?.createdAt) return; const endTimer = moment(billData.createdAt).add(2, "minutes"); // 初始计算当前时间到结束时间的真实剩余时长 const initDuration = endTimer.diff(moment()); setDuration(initDuration > 0 ? initDuration : 0); const interval = setInterval(() => { // 用函数式更新拿到最新的duration值进行计算 setDuration(prev => { if (prev <= 1000) { clearInterval(interval); return 0; } return prev - 1000; }); }, 1000); return () => clearInterval(interval); }, [billData?.createdAt]); return <>{getFinalTime(duration)}</>; }; export default CountDownTimer;
补充说明
- 用setDuration的函数式更新写法,可以保证每次计算都拿到最新的剩余时长,不会出现固定值计算的问题。
- 增加了倒计时归0后自动清除定时器的逻辑,避免资源浪费。
- 初始值计算当前时间到结束时间的差值,适配组件加载时已经过了一段时间的场景。
内容的提问来源于stack exchange,提问作者Kanti vekariya
相关产品推荐
相关产品推荐

