关于setState的异步更新

我们都知道setState是异步执行的;
事实上,setState本身的执行过程是同步的,只是因为在react的 合成事件与钩子函数 中它的执行顺序在更新之前,所以不能直接拿到更新后的值,形成了所谓的异步

那么请问setState是什么时候是同步的呢?
事实上它在ajax、原生事件与setTimeout中是同步的

今天主要是深入探讨一下关于setState为什么是异步的问题。
先来看一个例子。它是在面试里非常容易出现的一道题。

import React, {
    
     Component } from 'react';
class App extends Component {
    
    
    constructor(props) {
    
    
        super(props);
        this.state = {
    
     count:0 }
    }
    increase=()=>{
    
    
        this.setState({
    
    count:this.state.count+1});
        console.log(this.state.count);
        this.setState({
    
    count:this.state.count+1});
        console.log(this.state.count);
        setTimeout(()=>{
    
    
            this.setState({
    
    count:this.state.count+1});
            console.log(this.state.count);
            this.setState({
    
    count:this.state.count+1});
            console.log(this.state.count);
        })
    }
    render() {
    
     
        return ( 
            <div>
                <div>setState</div>
                <button onClick={
    
    this.increase}>btn</button>
            </div>
         );
    }
}

我们首先来分析一下它的整个过程哼,

因为onClick 是合成事件,其对应的函数 increase 中的 setState 会被放到 batch Update 的 queue 中做统一的更新,而且,当 state 中的属性名称相同时,后一次的 setState 会把上一次队列中的覆盖掉。
但是,异步任务中的 setState 并不会被放到 batch Update 的 queue 里面,所以里面的 setState 是同步的。

所以它的整个执行过程是这样的。
1、第一个 setState 放到 batchUpdateQueue 里。输出两个 count都是 0

2、第二个 setState 即将放到 queue 里面时,看到里面已经有一个 key = count 的 setState 了,于是,把那个 setState 替换掉。

3、setTimeout 整个被放到事件循环队列的宏任务队列里面

4、合成事件函数结束

5、batchUpdateQueue 批量执行 setState,count 此时为 1,因为 queue 里面只有一个 setState({count:this.state.count+1})。

6、count 此时被更新为 1

7、宏任务执行,同步执行 setState。

8、输出 2,3

总结:

  1. setState只有在和合成事件和钩子函数中是异步的;在原生事件和setTimeout中是同步的。
  2. setState的异步并不是说内部由异步代码实现,其本身的执行过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立即拿到更新之后的值,所以就形成了所谓的“异步”。
  3. setState的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout中不会批量更新,在“异步”中如果对同一个值进行多次setState,setState的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时setState 多个不同的值,在更新时会对其进行合并批量更新。

猜你喜欢

转载自blog.csdn.net/qq_45830543/article/details/111594581
今日推荐