setState详细解析
了解完上面的reactDOM重新render的过程之后,我们也需要关注数据的更新问题。
为什么要使用setState
开发中我们并不能通过直接修改state的值来让界面自动发生更新(虽然数据值本身虽然已经发生了变化,但是界面并没有发生更新),因为当我们修改了state之后,react并没有实现类似于vue2中的object.defineProperty或者vue3中的proxy的方式去监听数据变化从而自动刷新界面,在react中我们必须通过setState去告知render函数数据已经发生了变化(这一点个人感觉vue3中的ref、reactiveAPI类似于setState),这也就是为什么会有setState的原因了,即使在后面会使用hooks。至于setState是异步还是同步更新的问题,我们需要根据实际情况而定。
异步更新
this.state = {
message: "message"
}
btnClick() {
this.setState({
message: '测试'
})
//此时我们直接在这里打印,却发现结果并未发生改变依然是message,
console.log(this.state.message);//message
}
根据这段代码的输出结果为message可知setState是异步的操作,也就是说我们并不能在执行完setState之后立马拿到最新修改后的state,那么为什么将setState设计为异步呢?React的核心成员(redux的作者)在github https://github.com/facebook/react/issues/11527上面对这个问题有相对应的回复,简单总结下来就是:
(1)将setState设计为异步,可以显著的提高性能:因为如果state每修改一次setState都进行一次更新的话,那么意味着render函数会被频繁调用,导致界面不断的重新渲染,而这样的话效率肯定是很低的,因此最好的办法就是通过异步操作尽可能的获取到多个更新操作之后再去进行批量的更新。
(2)如果同步更新了state,但是还没有执行render函数或者render执行需要一段时间,那么就使得state和props无法保持一致性,因此就会在开发中产生很多的问题。
获取异步更新结果的方法
首先需要知道setState(更新的state,回调函数)是可以传入这两个参数的,以下是获取异步更新结果的两种方法:
方法一:在第二个参数回调函数中去获取异步更新的结果。
this.setState({
message: '测试'
}, () => {
console.log(this.state.message)
})
方法二:在componentDidUpdate生命周期函数中去直接获取(因为每次重新render时,都会触发这个函数)
componentDidUpdate() {
console.log(this.state.message);
}
同步更新以及结果获取
如果还是想使用同步的方式去更新state的话,以下是setState同步更新数据的两种方法:
方法一:将setState操作放到setTimeout计时器中去执行(无非也就是去等待render函数执行完成,从而达到state和props数据的一致性)
increment() {
setTime