关于react中setState的新理解

238 阅读2分钟

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的理解,如有错误,感谢大佬指出