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

React中setState与interval配合时currentExpVal始终为0,定时器无法停止

问题原因与解决办法

为什么currentExpVal始终是0?

你的useEffect依赖项是空数组[],这会让它只在组件首次渲染时执行一次。定时器的回调函数会形成闭包,捕获的是组件初始状态下的currentExpVal(也就是0)。

后续虽然通过setCurrentExpVal((prev) => prev + 1)正确累加了状态值,但定时器回调里的currentExpVal永远是闭包里保存的那个初始值0。所以currentExpVal < expValueRef.current的判断永远为真,永远不会触发清除定时器的逻辑。


修复方案

方案1:用Ref跟踪最新状态值

新增一个Ref来同步currentExpVal的最新值,这样定时器里能直接拿到当前的状态进行判断:

import React, { useEffect, useRef, useState } from "react";
import styles from "./Experience.module.scss";

type Props = {};

export const Experience: React.FC<Props> = (props: Props) => {
  const expValueRef = useRef(10);
  const [currentExpVal, setCurrentExpVal] = useState(0);
  const currentExpRef = useRef(currentExpVal);

  // 同步状态到Ref,确保Ref始终持有最新值
  useEffect(() => {
    currentExpRef.current = currentExpVal;
  }, [currentExpVal]);

  useEffect(() => {
    const intervalRef = setInterval(() => {
      if (currentExpRef.current < expValueRef.current) {
        console.info(currentExpRef.current, expValueRef.current);
        setCurrentExpVal((prev) => prev + 1);
      } else {
        console.info("clear");
        clearInterval(intervalRef);
      }
    }, 1500);

    // 组件卸载时清理定时器,防止内存泄漏
    return () => clearInterval(intervalRef);
  }, []);

  return (
    <div className={styles["exp-wrapper"]}>
      {currentExpVal}
    </div>
  );
};

方案2:给useEffect添加依赖并清理旧定时器

让useEffect依赖currentExpVal,每次状态更新时重新创建定时器,但要记得清理旧的定时器,避免多个定时器同时运行:

import React, { useEffect, useRef, useState } from "react";
import styles from "./Experience.module.scss";

type Props = {};

export const Experience: React.FC<Props> = (props: Props) => {
  const expValueRef = useRef(10);
  const [currentExpVal, setCurrentExpVal] = useState(0);

  useEffect(() => {
    // 已经达到目标值时,不再创建定时器
    if (currentExpVal >= expValueRef.current) return;

    const intervalRef = setInterval(() => {
      setCurrentExpVal((prev) => {
        // 在下一次更新前判断,如果即将达到目标,就清除定时器
        const nextVal = prev + 1;
        if (nextVal >= expValueRef.current) {
          clearInterval(intervalRef);
        }
        return nextVal;
      });
    }, 1500);

    // 清理旧定时器
    return () => clearInterval(intervalRef);
  }, [currentExpVal]);

  return (
    <div className={styles["exp-wrapper"]}>
      {currentExpVal}
    </div>
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 20:03:21