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

React中如何停止setInterval?速打游戏倒计时失效问题

问题原因分析

你的代码里let timer是在组件顶层声明的,组件每次因sec更新而重新渲染时,这个变量都会被重新创建,原来的定时器引用会直接丢失。当sec <= 0时执行clearInterval(timer),操作的其实是一个新的、未赋值的timer变量,自然无法停止之前创建的定时器。另外,直接在组件顶层写if(sec <=0)的逻辑,会在每次组件渲染时都触发,逻辑也不够严谨。

解决方案:用useRef保存定时器引用

React中要用useRef来存储定时器这类需要跨渲染保持引用的值,它的.current属性在组件整个生命周期内都不会随渲染重置。同时配合useEffect监听倒计时状态,双重保障定时器的清理,还能避免组件卸载时的内存泄漏。

修改后的代码如下:

import { useState, useRef, useEffect } from 'react';

const countdownValue = 15;

function TypingGameCountdown() {
  const [sec, setSec] = useState(countdownValue);
  const timerRef = useRef(null); // 用useRef持久化定时器引用

  function start() {
    // 启动前先清除已有定时器,避免重复创建导致倒计时加速
    if (timerRef.current) {
      clearInterval(timerRef.current);
    }
    setSec(countdownValue); // 重置倒计时数值
    timerRef.current = setInterval(() => {
      setSec(prevSec => {
        // 倒计时即将归0时直接清除定时器
        if (prevSec <= 1) {
          clearInterval(timerRef.current);
          return 0;
        }
        return prevSec - 1;
      });
    }, 1000);
  }

  // 监听sec变化,作为清理定时器的额外保障,同时处理组件卸载逻辑
  useEffect(() => {
    if (sec <= 0 && timerRef.current) {
      clearInterval(timerRef.current);
      timerRef.current = null; // 清空引用,避免无效调用
    }

    // 组件卸载时强制清除定时器,防止内存泄漏
    return () => {
      if (timerRef.current) {
        clearInterval(timerRef.current);
      }
    };
  }, [sec]);

  return (
    <div>
      <p>剩余时间:{sec}秒</p>
      <button onClick={start}>开始游戏</button>
    </div>
  );
}

export default TypingGameCountdown;
关键说明
  • useRef存储定时器:确保组件多次渲染后,始终能拿到同一个定时器的引用,不会丢失。
  • 启动前清理旧定时器:避免用户多次点击启动按钮创建多个定时器,导致倒计时速度异常。
  • setSec内部判断清理:在更新倒计时数值的同时直接处理归0逻辑,减少额外的状态监听开销。
  • useEffect兜底清理:既监听倒计时状态做保障,又在组件卸载时清理定时器,彻底避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 10:20:31