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

React useCallback闭包变量读取机制及示例中cb2重渲染后输出结果的技术问询

React useCallback闭包变量读取机制及示例中cb2重渲染后输出结果的技术问询

嘿,这个问题问到了React里闭包和useCallback结合时最容易踩的坑点,我给你一步步拆解清楚:

首先得搞懂两个核心点:useCallback的缓存逻辑,以及React组件渲染时的作用域隔离。

1. useCallback的缓存规则

useCallback的作用是根据依赖数组来决定是否返回新的函数引用:

  • 当依赖数组是空[]时,只有组件第一次渲染时会创建这个函数实例,之后不管组件怎么重渲染,只要依赖没变化(空数组永远不会变),就一直复用第一次创建的那个函数。
  • 你的示例里cb2就是这种情况,它从第一次渲染后就再也没被重新创建过。

2. 闭包与渲染作用域的绑定

React组件每次重渲染,都会重新执行一遍你的TestHook函数,每个渲染周期都有完全独立的函数作用域,里面的变量都是新声明的。而useCallback缓存的函数,会牢牢绑定它创建时那个渲染周期的作用域——也就是第一次渲染的作用域。

现在对应你的示例里cb2的输出,拆分两个变量的不同表现:

关于count(useState状态变量)

count是useState返回的状态变量,每个渲染周期的count都是当前状态的快照——简单说就是,第一次渲染时count是0,重渲染时新的作用域里count是1,这是两个完全独立的快照值。
但cb2是第一次渲染时创建的,它的闭包只能捕获第一次渲染时的count快照,所以不管之后怎么重渲染,cb2里的count永远是0。

关于countVal(普通let变量)

countVal是你在TestHook内部声明的普通变量,每次重渲染都会重新声明一个新的countVal(初始值0)。但这里有个关键细节:
你点击add按钮时,执行的是第一次渲染时创建的add函数——这个函数绑定的是第一次渲染作用域里的countVal。当你执行countVal++时,修改的是第一次渲染作用域里的那个countVal,而cb2刚好绑定的也是这个作用域的countVal引用,所以当cb2在重渲染后执行时,读取到的是已经被修改成1的那个变量值。

而重渲染时新声明的countVal=0是另一个完全独立的变量,和cb2没有任何关系。

对应示例的最终结果解释

当你点击一次add按钮后:

  1. add函数修改第一次渲染作用域里的countVal为1,然后setCount触发重渲染。
  2. 重渲染时,组件执行新的TestHook,创建新的count(值1)、新的countVal(值0),但cb2还是第一次渲染的那个函数。
  3. 此时执行cb2(),它会输出:
    • count:第一次渲染的快照值0
    • countVal:第一次渲染作用域里被修改后的1

这就是你看到cb2()第二次输出0, 1的原因啦!

备注:内容来源于stack exchange,提问作者2tuzi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 10:48:02