React顺序运行两个倒计时器时第二个刚启动就停止如何解决
问题核心原因
- 组件实例被复用:React 对同一父组件、同一渲染位置的同类型组件,默认会复用已有实例,不会重新初始化内部状态。你切换渲染第二个 Timer 时,组件实例没有重建,内部的
timeLeft状态还是第一个计时器结束时的0,所以会直接触发结束逻辑,表现为刚启动就停止。 - Timer 组件本身存在逻辑缺陷:
useEffect没有声明依赖数组,每次组件重渲染都会创建新的定时器,既会导致内存泄漏,也会打乱计时逻辑- 定时器回调存在闭包问题,捕获的
timeLeft永远是初始渲染时的值,无法正确完成递减 - 计时结束的判断逻辑没有和定时器逻辑配合,执行时机不符合预期
修复方案
你可以选择任意一种方式解决实例复用问题,同时修正 Timer 组件的逻辑缺陷即可:
- 给两个 Timer 组件添加不同的
key属性,强制 React 卸载旧实例、创建新实例,自动初始化状态 - 优化 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
相关产品推荐
相关产品推荐

