React的useState setter回调会多次执行吗?计数异常问题求解
问题根因
这个现象是React 18+开发环境下严格模式(StrictMode)的特性导致的,和你猜想的Fiber架构设计相关,但不是console被重写隐藏日志这么离谱的设计,具体逻辑如下:
- React 18之后,开发环境下如果项目用了
<StrictMode>包裹根组件,所有传递给状态更新函数(比如你这里的setList)的回调会被故意执行两次,目的是提前暴露非幂等的状态更新逻辑问题,帮你提前排查生产环境可能出现的bug。 - 为了避免两次执行的日志刷屏干扰调试,React开发环境会临时屏蔽第二次执行状态更新回调时的所有console输出,所以你看不到第二次
++counter的执行日志,只会发现counter的数值莫名其妙跳了2。 - 你的
counter是模块级别的全局可变变量,在状态更新回调里执行++counter属于在更新逻辑中引入了外部副作用,本身就是非幂等操作:第一次执行回调counter加1,生成的列表比如X1,X2会被React直接丢弃;第二次隐式执行时counter已经是2,再加1就变成3,最终返回的列表是X1,X3,这才是React实际用来更新状态的值,所以控制台打印的第一次执行的列表和实际渲染结果不一致。 - 你把
++counter移到setList回调外部后运行正常的原因是:严格模式只会重复执行状态更新回调,不会重复执行整个onClick事件处理函数,所以counter每次点击只会加1,更新回调里读取到的就是正确的数值。
验证方法
你可以找到项目入口文件,把包裹App组件的<StrictMode>标签去掉,再运行代码点击按钮,结果就会完全符合你的预期。另外这个重复执行的逻辑只会出现在开发环境,生产环境打包后不会有这个问题。
内容的提问来源于stack exchange,提问作者0x24a537r9
相关产品推荐
相关产品推荐

