setState是异步还是同步?
通常在面试react相关问题的时候就会被面试官问到setState是同步还是异步?
如果你答:在react的生命周期函数或者作用域下为异步,在原生的环境下为同步。
获取你觉得你自己答对了,实际上你并没有答对完。接下来我们来分析不同情况下的setState。
同步:
那在什么情况下是同步呢?在没有使用Concurrent的时候
原生环境下
componentDidMount(){
document.body.addEventListener('click', this.changeNum, false);
setTimeout(()=>{
this.setState({num:1})
console.log('--1--',this.state.num)
},0)
}
changeNum = () => {
this.setState({
num:2
})
console.log('--2--',this.state.num)
}
结果为--1-- 1 --2-- 2 结果得到的num是改变后的,所以是同步的,这里我就不多赘述了
flushSync函数下
随着react 17的发布,ReactDOM.flushSync已经允许在生命周期中使用了(但是会waring,额尴尬)
click(){
console.log('--1--',this.state.num)
flushSync(()=>{
this.setState({
num:1
})
})
console.log('--2--',this.state.num)
}
结果为--1-- 0 --2-- 1 结果得到的num是改变后的,所以是同步的,总所周知,Fiber的诞生让渲染变得更加人性化,react 会先渲染优先级高的,然后将js线程空闲出来先干其他的事,如动画的渲染,完了之后再渲染优先级低的。而flushSync就可以提升渲染的优先级。
react环境下的伪异步
click = () => {
console.log('--1--',this.state.num)
this.setState({
num:1
},()=>{
console.log('--3--',this.state.num)
})
console.log('--2--',this.state.num)
}
结果为--1-- 0 --2-- 0 --3-- 1 虽然结果看起来好像是异步的,但是其实这是个伪异步。这里的setState只是单纯的将新的state传入updateQueue这个链表上,也就是更新队列,等点击事件结束后,才会触发内部的回调函数,然后真正去更新state和重新渲染。
真正的异步 ConcurrentMode组件包裹
当使用了Concurrent组件的时候,就会进行真正的异步更新模式,当然也无法立即获取最新的state,它执行的时候时候使用了(postMessage)。但是这个模式还在实验阶段,也就是说当前稳定版本的react是无法使用的。有想了解详细介绍的可以去react官网 reactjs.bootcss.com/docs/concur… 以上是我对setState的理解,如有错误,感谢大佬指出