React - setState

React中,对于setState的理解,以及获取同步更新状态的方法。

异步原理

之前看过一些文章,有这么个说法,setState在合成事件中是“异步”更新,在原生事件中是“同步”更新。这个说法没错,但总感觉怪怪的,直到看到了鲨叔的文章(文末链接),才彻底理解。

批量更新是因,异步执行是果。

这里简单的提一下:在当前版本的React中,为了提升性能,会将多个setState进行合并更新,其实本身的代码上是同步的。只是setState获取状态都是在render()前操作的,而合并更新又会进行一个短暂的调度延迟,所以我们获取更新状态的时候在感觉上是“异步”的。

同步方法

回调函数

setState的第二个参数可以传入一个回调函数,会在状态更新完毕后触发,即可实现同步流程。也可以在第一个setState的回调函数中嵌入第二个setState,形成链式调用链,顺序是可控的。

1
2
3
4
5
6
7
8
9
10
this.setState({
firstLoad: true,
}, () => {
console.log('第一次更新完成')
this.setState({
secondLoad: true
}, () => {
console.log('第二次更新完成')
})
});
async/await

通过回调函数控制同步更新的方式会产生代码嵌套,如果嵌套层数过多会感觉不太直观,也就是回调地狱。因此,我们也可以通过封装一个Promise,使用async/await的方式来改造它,其实本质上还是用了上文的回调函数

1
2
3
4
5
6
7
8
9
10
11
setStateAsync(state) {
return new Promise((resolve) => {
this.setState(state, resolve)
})
}

async componentDidMount() {
const res = await fetch('/api/user/info')
const { username } = res
await this.setStateAsync({ username: username })
}
状态计算函数

除了使用回调函数这种方式监听更新结果,我们也可以在setState的第一个参数中传入一个状态计算函数,而不是普通对象。函数中可以传入两个参数,state表示上一个状态值,props表示当前的状态。

1
2
3
this.setState((state, props) => ({
counter: state.counter + props.increment
}))

参考文献

深入react的setState机制

查看评论