react的setState到底是同步还是异步?


这是一道经典 react 面试题,之前还有点疑惑,为了探究真理,特来加以总结。

答案:react 的 setState 既可能是同步的,也可能是异步的。 准确地说,在 React 内部机制能检测到的地方, setState 就是异步的;在 React 检测不到的地方,例如 setInterval,setTimeout 里,setState 就是同步更新的。

在介绍这个问题之前,我们先来看一下一个例子:

state = {
    number:1
};
componentDidMount(){
    this.setState({number:3})
    console.log(this.state.number) //1
}

看完这个例子,也许很多小伙伴会下意识的以为 setState 是一个异步方法,但是其实 setState 并没有异步的说法,之所以会有一种异步方法的表现形式,归根结底还是因为 react 框架本身的性能机制所导致的。因为每次调用 setState 都会触发更新,异步操作是为了提高性能,将多个状态合并一起更新,减少 re-render 调用。

试想一下如果在组件中有以下这样一段代码执行:

for (let i = 0; i < 100; i++) {
  this.setState({ num: this.state.num + 1 });
}

如果 setState 是一个同步执行的机制,那么这个组件会被重新渲染 100 次,这对性能是一个相当大的消耗。

显然,React 也是想到了这个问题,因此对 setState 做了一些特殊的优化:

❝ React会将多个setState的调用合并为一个来执行,也就是说,当执行setState的时候,state中的数据并不会马上更新
❞

这也很好的印证了刚才提到的那个例子。

但是往往在实际的开发工作中,我们可能需要同步的获取到更新之后的数据,那么怎么获取呢?下面介绍几种常用的方法:

回调函数
setState 提供了一个回调函数供开发者使用,在回调函数中,我们可以实时的获取到更新之后的数据。还是以刚才的例子做示范:

state = {
    number:1
};
componentDidMount(){
    this.setState({number:3},()=>{
        console.log(this.state.number)//3
    })
}

可以看见此时控制台打印的数据是最新的数据。这也完美的印证了我们的猜想是正确的。

总结:

❝ setState本身并不是异步,只是因为react的性能优化机制体现为异步。在react的生命周期函数或者作用域下为异步,在原生的环境下为同步。
❞

文章作者: BiLiang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 BiLiang !
评论
  目录