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

React函数组件setInterval失效,Timer组件停止重置按钮异常如何修复

Timer组件问题排查与修复方案

问题根源

所有功能异常的核心原因是useRef使用错误,导致定时器ID没有被正确存储,后续Stop、Reset操作无法清除正在运行的定时器,定时器持续执行setWatchData逻辑,覆盖了手动修改状态的结果。

具体错误点

  • 启动定时器时直接覆盖了ref对象本身,而非将定时器ID存储到timer.current属性,导致后续无法正确获取运行中的定时器ID
  • 组件销毁的useEffect清理函数中,错误将ref对象本身传入clearInterval,而非timer.current存储的ID
  • setInterval未指定执行间隔,会以浏览器最小允许间隔高频执行,产生不必要的性能开销
  • handleLap方法中直接取闭包中的watchData.timestamps拼接,存在闭包旧值风险

修复后完整代码

import React, { useEffect, useState, useRef } from "react";

const initialState = {
  status: false,
  runningTime: 0,
  timestamps: []
};

export const Timer = () => {
  const [watchData, setWatchData] = useState(initialState);
  const timer = useRef(null);

  useEffect(() => {
    return () => {
      clearInterval(timer.current);
    };
  }, []);

  const getUnits = (time) => {
    const seconds = time / 1000;

    const min = Math.floor(seconds / 60).toString();
    const sec = Math.floor(seconds % 60).toString();
    const msec = (seconds % 1).toFixed(3).substring(2);

    return `${min.padStart(2, '0')}:${sec.padStart(2, '0')}:${msec}`;
  };

  const handleClick = () => {
    const { status } = watchData;

    if (!status) {
      const startTime = Date.now() - watchData.runningTime;
      timer.current = setInterval(() => {
        setWatchData((prevState) => ({
          ...prevState,
          status: true,
          runningTime: Date.now() - startTime
        }));
      }, 10);
    } else {
      clearInterval(timer.current);
      setWatchData((prevState) => ({ ...prevState, status: false }));
    }
  };

  const handleReset = () => {
    clearInterval(timer.current);
    setWatchData({ ...initialState });
  };

  const handleLap = () => {
    const timestamp = getUnits(watchData.runningTime);
    setWatchData((prevState) => ({
      ...prevState,
      timestamps: [...prevState.timestamps, timestamp]
    }));
  };

  return (
    <>
      <p>{getUnits(watchData.runningTime)}</p>
      <button onClick={handleClick}>
        {watchData.status ? "Stop" : "Start"}
      </button>
      <button onClick={handleReset}>Reset</button>
      <button onClick={handleLap}>Lap</button>
      {watchData.timestamps.length > 0 && (
        <ul>
          {watchData.timestamps.map((t, index) => (
            <li key={index}>{t}</li>
          ))}
        </ul>
      )}
    </>
  );
};

内容的提问来源于stack exchange,提问作者Mrs.Smith

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 22:18:04