React类组件中setState回调为何无需this即可获取前序state
setState向回调传入前序state的原理解答
你的猜测是准确的,这个机制完全来自类组件继承的React.Component父类的内置实现,和JavaScript语言本身无关,具体逻辑如下:
setState是定义在React.Component原型上的内置方法,所有类组件继承该父类后,才能调用这个方法触发状态更新,方法内部本身维护了对应组件实例的状态更新队列、批量更新逻辑。- React设计这个函数传参的核心原因,是
setState默认是异步批量执行的:如果你在同一个交互事件、生命周期里连续多次调用setState,直接读取this.state拿到的永远是当前已经渲染到页面上的旧状态,无法获取同批次更新中前序setState生成的中间状态,很容易出现状态更新被覆盖的问题。举个最常见的反例:如果连续写3次
this.setState({count: this.state.count +1}),三次读取到的this.state.count都是0,最终count只会被更新为1,和预期的3完全不符。 - 当你给
setState传入函数类型的更新器时,React在批量处理更新队列的阶段,会严格按照入队顺序逐个执行这些更新器函数:执行每一个更新器之前,React都会把当前队列里累计的最新待提交状态、当前最新的props作为第一、第二个参数传入,拿到更新器返回的新状态片段后,会把它合并到累计状态中,再把这个最新的累计状态传给下一个排队的更新器。等队列里所有更新器执行完成,React才会把最终的状态挂载到组件实例的this.state上,触发组件重渲染。 - 你示例代码里
setState之后立刻打印this.state拿到旧值,也是这个异步批量机制导致的——打印逻辑执行时,更新队列还没被处理,this.state还没有被替换为最新值。
另外你示例代码里的更新器写法有个冗余问题:(state) => ({ state, ...{ count: state.count + 1 } })会把整个旧state作为名为state的字段重复挂载到新的state对象上,正常只需要写(state) => ({ count: state.count + 1 })即可完成count的累加。
内容的提问来源于stack exchange,提问作者bryantjo
相关产品推荐
相关产品推荐

