You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Moment.js实现2分钟倒计时时计时器停在1:59无法递减问题求助

问题原因
  1. useEffect中定义的duration是固定常量,值恒为初始2分钟对应的毫秒数。setInterval回调每次执行时,都是用这个固定值减1000,得到的结果永远是119000毫秒(对应1分59秒),更新到state后不会再变化,所以计时器卡住。
  2. duration state初始化值为null,首次调用getFinalTime时入参为空可能引发异常。
  3. 原有逻辑计算的初始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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 01:15:06