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

React使用setInterval实现类番茄钟定时器重启后sessionSeconds不更新问题

问题根因
  • 闭包陷阱:sessionSeconds是startTimer的局部变量,setInterval回调形成的闭包只会捕获函数执行时的上下文,后续状态更新后旧闭包无法拿到最新的iswork、work、rest等值
  • 定时器引用未持久化:你没有将定时器ID存储在useRef中,组件重渲染后原有定时器引用会丢失,无法正确清理旧定时器,容易出现多个定时器同时运行的问题
  • 变量未定义:判断条件中的duration没有任何赋值逻辑,实际应该判断sessionSeconds是否小于等于0
  • 未实时更新状态:你只在切换时段的时候调用updateTime,秒数变化时没有更新remainingTime,页面不会实时刷新计时
修复后代码
import { useState, useRef, useEffect } from 'react';

const TimeTracker = () => {
  const [work, setWork] = useState(25);
  const [rest, setRest] = useState(5);
  const [remainingTime, setRemainingTime] = useState(work * 60);
  const [iswork, setIswork] = useState(true);
  // 用useRef存储定时器id,持久化引用避免渲染后丢失
  const intervalRef = useRef(null);

  const updateTime = (seconds) => {
    setRemainingTime(seconds);
  };

  const startTimer = () => {
    // 先清除已有定时器,避免多定时器并行
    if (intervalRef.current) {
      clearInterval(intervalRef.current);
    }
    let sessionSeconds = iswork ? work * 60 : rest * 60;
   
    intervalRef.current = setInterval(() => {
      sessionSeconds--;
      // 实时更新页面显示的剩余时间
      updateTime(sessionSeconds);
      if (sessionSeconds <= 0) {
        // 切换工作/休息状态
        setIswork(prev => !prev);
        // 重启计时器进入下一个时段
        startTimer();
      }
    }, 1000);
  };

  // 组件卸载时清除定时器,避免内存泄漏
  useEffect(() => {
    return () => {
      if (intervalRef.current) {
        clearInterval(intervalRef.current);
      }
    };
  }, []);

  return (
    <div>
      <p>
        {/* 可自行添加时间转换逻辑,把秒数转换为时分秒格式展示 */}
        {remainingTime}
      </p>
      <button onClick={startTimer}>start timer</button>
    </div>
  );
};
可选优化建议
  • 可以把定时器逻辑放到useEffect中,通过监听iswork的变化自动切换时段,不用手动在定时器回调里调用startTimer
  • 如果需要新增暂停、重置功能,直接操作intervalRef.current清除定时器、重置对应状态即可

内容的提问来源于stack exchange,提问作者slawckaJS

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 21:15:05