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

React useState初始化函数无执行痕迹导致counter意外自增问题求助

问题原因分析

核心原因

该现象是 React 18+ 开发环境严格模式(StrictMode) 的特性导致的,和闭包、Hook 本身的逻辑无关。

具体运行流程

React 18 开启严格模式后,开发环境下会对所有组件执行「首次挂载→立即卸载→二次挂载」的逻辑,目的是提前暴露组件清理逻辑、副作用不符合规范的问题,该行为只会在开发环境出现,生产环境不会触发。
你的代码运行的完整流程如下:

  1. 初始全局counter值为 0
  2. 第一次挂载Child组件:
    • 执行useState的惰性初始化回调,counter自增为 1,打印标记(1)的日志
    • 执行标记(2)的日志,输出id为1
    • 该次挂载的组件会被立即卸载,相关实例被丢弃
  3. 第二次挂载Child组件:
    • 这是最终保留在页面上的组件实例,useState会重新执行初始化回调,counter自增为 2
    • 标记(1)(2)的日志正常触发,但 React 会默认静默严格模式下二次挂载的所有console.log输出,所以控制台看不到这部分日志
    • 最终组件拿到的id是 2,按钮点击回调的闭包捕获的就是这个值,全局counter此时也为 2
      所以点击按钮时会输出id: 2 counter: 2,本质是实际展示的组件是第二次挂载的实例,而第一次挂载的日志没有被静默,形成了初始化逻辑只执行了一次的错觉。

验证方法

  • 移除项目外层的<StrictMode>标签后重新运行,就会得到预期的id:1 counter:1的点击输出
  • 在useState的初始化回调中加入debugger断点,可以明确看到回调执行了两次

方案优化建议

要实现「为组件调用位点生成唯一ID」的需求,React 18 已经提供了原生的useId Hook,不需要自己维护全局计数器,可以直接替换实现,避免全局可变变量带来的各类问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 12:27:03