Daily Notes

Just Some Notes

React中setState方法的同步与异步

this.setState方法内部做了什么?

调用this.setState方法后,先进行状态合并,并会触发状态更新,重新调用组件的render方法,render方法执行结束后会产生新的虚拟dom,最后React内部会对组件的新旧虚拟dom进行diff操作,得到针对旧虚拟dom的patch,最后根据patch来更新dom结构,实现视图更新.

this.setState的同步和异步,为什么这样处理?

React的setState方法本质上都是同步操作,所谓异步,指的是将一系列的setState操作先收集起来,最终在函数执行结束时进行状态合并后再进行批量执行.

之所以这样做,是因为如前文所述,每次调用setState方法都会触发视图更新,先将多次setState的调用收集起来,最终根据每次setState调用的状态参数进行状态合并后会得到最终的组件状态,这样一来,虽然调用了多次this.setState,但最终只会调用一次组件的render方法,视图也只会更新一次.

同步和异步分别发生在什么时机?

如前文所述,在函数的执行过程中,如果React想对this.setState进行“异步”操作,必须要能知晓这个函数什么时候会执行结束,在React中,组件生命周期函数的执行完全由React控制,事件处理程序由于合成事件的机制也被React所控制,因此在这两类函数里的this.setState都是“异步”处理,对于setTimeout和setInterval以及Promise回调这一类不在React管控范围内的函数里面,所有的this.setState就只能是同步处理了.

import React from 'react';

class Foo extends React.Component {

    state = {
        a: 'a',
    }

    bar() {
        this.setState({
            a: 'A'
        });
        console.log(this.state.a); // 'a'
    }

    componentDidMount() {
        setTimeout(() => {
            this.setState({
                a: 'A'
            });
            console.log(this.state.a); // 'A'
        }, 0);

        Promise.resolve().then(() => {
            this.setState({
                a: 'A'
            });
            console.log(this.state.a); // 'A'
        });

        this.setState({
            a: 'A'
        });
        console.log(this.state.a); // 'a'
    }

    render() {
        return (
            <div onClick={this.bar}>bar</div>
        )
    }
}