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

React计数器中setInterval为何形成闭包?闭包引发计数异常解析

为啥这个React计数器只能跑到2?

先看你的代码:

import React, { useEffect, useState } from "react";

function Counter() {
  const [count, setCount] = useState(1);

  useEffect(() => {
    const id = setInterval( () => {
      console.log("interval callback triggered");
      setCount(count + 1); // This effect depends on the `count` state
    }, 1000);
    return () => clearInterval(id);
  }, []); // 🔴 Bug: `count` is not specified as a dependency

  return <h1>{count}</h1>;
}

export default Counter;

先纠正一个误区:箭头函数也会形成闭包

你说()=>{}不会创建闭包是错的——箭头函数和普通函数一样,会捕获它定义时所在作用域的变量,形成闭包。这里的闭包就是setInterval里的那个箭头回调,它捕获了外层useEffect回调作用域里的count变量。

为什么计数器只能到2?

  1. 组件第一次渲染时,count是1,此时useEffect执行(依赖是空数组,只跑一次),创建了定时器。这个定时器的回调里,count被闭包钉死在1了。
  2. 1秒后回调触发,执行setCount(1+1),count变成2,组件重新渲染。
  3. 但因为useEffect的依赖是空数组,第二次渲染时useEffect不会重新执行,原来的定时器还在跑——它的回调里的count还是第一次渲染时的1!
  4. 之后每次定时器触发,都是把count设置成1+1=2,所以页面上永远显示2,再也涨不上去。

两种修复方法

方法1:把count加入useEffect的依赖数组

每次count变化,useEffect就重新执行,清除旧定时器,创建新的,新回调会捕获最新的count值:

useEffect(() => {
  const id = setInterval(() => {
    setCount(count + 1);
  }, 1000);
  return () => clearInterval(id);
}, [count]); // 加入count作为依赖

方法2:用函数式更新,跳过闭包捕获

直接让React给你传上一次的状态值,不需要依赖当前的count:

useEffect(() => {
  const id = setInterval(() => {
    setCount(prevCount => prevCount + 1); // 用函数式更新获取上一次状态
  }, 1000);
  return () => clearInterval(id);
}, []); // 不需要依赖count

内容的提问来源于stack exchange,提问作者Nicolas S.Xu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 09:15:35