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

React顺序运行两个倒计时器时第二个刚启动就停止如何解决

问题核心原因
  • 组件实例被复用:React 对同一父组件、同一渲染位置的同类型组件,默认会复用已有实例,不会重新初始化内部状态。你切换渲染第二个 Timer 时,组件实例没有重建,内部的timeLeft状态还是第一个计时器结束时的0,所以会直接触发结束逻辑,表现为刚启动就停止。
  • Timer 组件本身存在逻辑缺陷:
    1. useEffect没有声明依赖数组,每次组件重渲染都会创建新的定时器,既会导致内存泄漏,也会打乱计时逻辑
    2. 定时器回调存在闭包问题,捕获的timeLeft永远是初始渲染时的值,无法正确完成递减
    3. 计时结束的判断逻辑没有和定时器逻辑配合,执行时机不符合预期
修复方案

你可以选择任意一种方式解决实例复用问题,同时修正 Timer 组件的逻辑缺陷即可:

  1. 给两个 Timer 组件添加不同的key属性,强制 React 卸载旧实例、创建新实例,自动初始化状态
  2. 优化 Timer 组件逻辑,监听duration属性变化,变化时自动重置timeLeft状态

完整修复代码

import React, { useEffect, useState } from 'react';
    
function App() {
  const [timer1Up, setTimer1Up] = useState(false);
  const [timer2Up, setTimer2Up] = useState(false);
  if(!timer1Up) {
    return <Timer key="timer1" duration={3} setTimeUp={setTimer1Up}/>
  }
  if(timer1Up && !timer2Up) {
    return <Timer key="timer2" duration={6} setTimeUp={setTimer2Up}/>
  }
  if(timer1Up && timer2Up) {
    return <>Out of all your time buddy!!</>
  }
  return <>I have no purpose</>;
}

interface TimerProps {
  duration: number;
  setTimeUp: (value: boolean) => void;
}

const Timer = (props: TimerProps) => {
  const [timeLeft, setTimeLeft] = useState(props.duration);

  useEffect(() => {
    if (timeLeft === 0) {
      props.setTimeUp(true);
      return;
    }
    const timer = setTimeout(() => {
      setTimeLeft(prev => prev - 1);
    }, 1000);
    return () => clearTimeout(timer);
  }, [timeLeft, props.setTimeUp]);

  return <>{timeLeft} s</>
}

export default App;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 12:45:07