React严格模式下副作用判定及useState更新翻倍问题咨询
核心原理说明
首先明确React严格模式在开发环境的运行规则:所有传入useState更新器、useMemo、useReducer的函数都会被重复调用两次,目的是主动暴露不符合纯函数要求的代码逻辑。
两个更新函数的本质差异
你遇到的差异核心是两个setXxx传入的更新函数,一个是有副作用的非纯函数,另一个是无副作用的纯函数:
- 第一个更新函数
() => increaseCount1():内部修改了模块全局作用域下的普通变量count,这个变量不属于React托管的状态,每次调用函数都会永久改变外部变量的值,这就是典型的副作用。 - 第二个更新函数
() => countState2 + 1:仅读取当前渲染周期闭包捕获的React托管状态countState2,没有修改任何外部变量,相同输入永远返回相同结果,属于纯函数。
具体执行过程拆解
Btn1点击后的执行流程:
- 触发点击事件,
setCountState接收更新函数进入处理逻辑 - 严格模式第一次调用更新函数:执行
++count,全局count从0变为1,返回值1 - 严格模式第二次调用更新函数:再次执行
++count,全局count从1变为2,返回值2 - React最终将第二次调用的返回值2作为新状态赋值给
countState,页面就显示为加了2的结果
Btn2点击后的执行流程:
- 触发点击事件,
setCountState2接收更新函数进入处理逻辑 - 严格模式第一次调用更新函数:读取当前闭包内的
countState2值(比如当前是0),返回0+1=1,没有修改任何外部变量 - 严格模式第二次调用更新函数:读取的还是当前闭包内未改变的
countState2值0,还是返回0+1=1 - React最终将返回值1作为新状态赋值给
countState2,符合预期
正确的编码规则
React要求所有传入状态更新器、计算缓存的函数必须是纯函数,满足两个要求:
- 相同输入永远返回相同输出
- 不修改任何函数外部的变量、不触发外部可观测的变化(比如修改全局变量、修改DOM、发起请求等都属于副作用)
如果要修改外部变量,请把逻辑放到状态更新函数之外,或者直接使用React托管的状态做更新,比如用setCountState(prev => prev + 1)的写法即可避免该问题。
内容的提问来源于stack exchange,提问作者Joji
相关产品推荐
相关产品推荐

