React系列之setState

257 阅读2分钟

本文将围绕setState展开以下相关知识点

  1. setState的基础语法

  2. setState是同步还是异步的?

  3. 为什么setState在react中要设计为异步的?

  4. 代码验证

一,setState的基础语法:

setState(updater[, callback])

第一个参数updater:函数或者对象类型;

第一个参数updater为函数时:

// 写法一
this.setState((state, props) => {
    return {
        counter: state.counter + props.num
    }
})
// 写法二
this.setState((state, props) => ({
    counter: state.counter + props.num
}))

第一个参数updater为对象类型时:

this.setState({
    counter: 23
})

注意:如果后续更新的state状态要使用当前state的状态值时:

// 不建议这么写
this.setState({
    counter: this.state.counter + 10
});
// 建议这么写(使用函数写法)
this.setState((state) => ({
    counter: state.counter + 10
}));

第二个参数callback

// 初始化的state
this.state = {
    counter: 0
};
....
// 更新counter
this.setState((state) => ({counter: state.counter + 10 }), () => {
    console.log(this.state.counter);
})

那么,callback回调函数是在什么时候执行的?如下为官网提供的答案:

不熟悉的小伙伴们,以后在面试时千万别再说setState的第二个参数callback是同步执行的哦,说明你连官网都没看完

二,setState是同步的还是异步的?

1,setState并不是单纯的同步或者异步的,它的执行效果会因调用场景的不同而表现不同;

2,在合成事件及生命周期方法中表现为异步,在addEventListener、setTimeout、setInterval等原生事件中表现为同步;

3,在源码中,通过isBatchingUpdates来判断的,如果isBatchingUpdates为true,则将state状态存进state队列中进行批量合并后异步更新,如果为isBatchingUpdates为false,则执行同步更新。

三,为什么setState在react中要设计为异步的?

做异步设计是为了性能优化、减少渲染次数,React团队还补充了两点(源址):

1,保持内部一致性,确保内部状态提升是安全的。

保持state与props的一致性,如果setState改为同步方式,state得到更新,而props却不是。

2,启用并发更新

setState根据数据来源不同,分配不同的优先级来完成异步渲染。

四,代码测试验证

componentDidMount(){
    this.setState({
        count: this.state.count + 1
    });
    console.log('count11=', this.state.count);
    this.setState({
        count: this.state.count+ 1
    });
    console.log('count12=', this.state.count);

    setTimeout(() => {
       console.log('count20=', this.state.count); 
       this.setState({
           count: this.state.count + 1
       });
       console.log('count21=', this.state.count);
       this.setState({
            count: this.state.count + 1
       });
       console.log('count22=', this.state.count);
    }, 0);
}
// 执行结果如下:
count11= 0
count12= 0
count20= 1
count21= 2
count22= 3