因为this.setState(当使用class定义一个组件时)与useState(用函数定义一个组件时),他们改变渲染状态的时候是异步生效的。因为改变他们会相应的渲染页面,JS是单线程应用,渲染页面代价较高,所以所有的state的改变都是异步进行的!!!!
1.)setState操作是异步的,并且为了性能提升而进行批处理。这在setState的文档中有解释。
setState()不会立即改变this.state,但会创建挂起状态转换。调用此方法后访问this.state可能会返回现有值。无法保证对setState的调用进行同步操作,并且可以对调用进行批处理以提高性能。
2.)为什么它们会使setState异步,因为JS是单线程语言,并且此setState不是WebAPI或服务器调用:
这是因为setState改变了状态并导致重新渲染。这可能是一项昂贵的操作,并使其同步可能会使浏览器无响应。
因此,setState调用是异步的以及批处理以获得更好的UI体验和性能。
setState意图是异步的,在Dan Abramov的链接解释中有一些非常好的理由。这并不意味着它总是异步的 - 它主要意味着你不能依赖它是同步的。ReactJS考虑了您正在更改状态的场景中的许多变量,以确定何时state应该实际更新并重新呈现组件。
一个简单的例子来说明,如果你打电话setState作为对用户操作的反应,那么state可能会立即更新(虽然,你再也不能指望它),所以用户不会感到任何延迟,但如果你打电话setState 为了响应ajax调用响应或其他一些不是由用户触发的事件,那么状态可能会稍微延迟更新,因为用户不会真正感受到这种延迟,并且它会通过等待来提高性能批处理多个状态一起更新并重新渲染DOM的次数更少
排队所有setState调用
在上下文中执行最后一个方法后回到此队列(在本例中为divCountHandler)
将在同一上下文中的多个setState调用内发生的所有对象变换(例如,单个事件阶段中的所有方法调用都是相同的上下文)合并为一个单个对象变异语法(合并是有意义的,因为这就是我们可以独立更新状态属性的原因在setState()中首先)
并将其传递给一个单独的setState()以防止由于多个setState()调用而重新呈现(这是一个非常原始的批处理描述)。
反应运行的结果代码:
this.setState({
updatedByDiv: 'Div',
updatedByBtn: 'Button',
counter: this.state.counter + 1
})
要停止此行为,不要将对象作为参数传递给setState方法,而是传递回调。
divCountHandler = () => {
this.setState((prevState, props) => {
return {
updatedByDiv: 'Div',
counter: prevState.counter + 1
};
});
console.log('divCountHandler executed');
}
btnCountHandler = () => {
this.setState((prevState, props) => {
return {
updatedByBtn: 'Button',
counter: prevState.counter + 1
};
});
console.log('btnCountHandler executed');
}
在最后一个方法完成执行并且react返回以处理setState队列之后,它只是为每个排队的setState调用回调,并传入前一个组件状态。
这种方式反应可确保队列中的最后一个回调更新其所有先前的对应物已经完成的状态。