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

React.js使用useEffect Hook更新自增计数器卡顿问题

问题根因

你的代码有4个核心bug,直接导致定时器堆积、逻辑失效,出现卡顿、数值跳变:

  • 定时器只建不清,越积越多:useEffect依赖是counter,每次counter变化都会重新执行effect,每次执行都会新建一个2秒触发的定时器,但你从来没有保存旧定时器的ID做清理,运行几秒后就会有几十个甚至上百个定时器同时跑,同时修改counter值,自然会跳变、卡顿。
  • 判断条件语法写错:你写的counter => 1200是定义箭头函数,根本不是大于等于判断(正确的大于等于是>=)。JS里函数本身转布尔值永远为真,这个if的前半段判断完全失效。
  • 清除定时器的写法完全无效:clearInterval必须传入对应setInterval返回的定时器ID才能清掉目标定时器,你代码里clearInterval(setInterval(handleCounter, 2000))的逻辑是:先新建一个定时器,立刻把这个新定时器的ID传进去清掉,之前创建的所有旧定时器根本没被处理,会一直在后台运行。
  • 状态更新踩了闭包陷阱:handleCounter里直接写setCounter(counter + 1),定时器触发时拿到的是创建那个定时器时刻闭包捕获的旧counter值,多个定时器同时触发时会反复基于旧值计算,出现数值跳变、增长顺序混乱的问题。
基础修复代码
const [counter, setCounter] = useState(1200)
useEffect(() => {
  // 数值到上限直接退出,不创建定时器
  if (counter >= 1364) return
  // 保存当前定时器ID,用于后续清理
  const timerId = setInterval(() => {
    // 用函数式更新拿最新值,避免闭包旧值问题
    setCounter(prev => prev + 1)
  }, 2000);
  // effect重跑/组件卸载时,清理当前定时器,避免堆积
  return () => clearInterval(timerId)
}, [counter])
更优写法(无需重复重建定时器)

上面的写法每次counter变化都会重建定时器,其实可以把依赖去掉,把判断逻辑放到状态更新里,性能更好:

const [counter, setCounter] = useState(1200)
useEffect(() => {
  const timerId = setInterval(() => {
    setCounter(prev => {
      // 数值到上限时清除定时器,不再更新
      if (prev >= 1364) {
        clearInterval(timerId)
        return prev
      }
      return prev + 1
    })
  }, 2000);
  // 组件卸载时清理定时器
  return () => clearInterval(timerId)
}, [])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 23:39:35