前言
这篇文章主要是因为自己在学习React中setState的时候,产生了一些疑惑,所以进行了一定量的收集资料和学习,并在此记录下来
引入
使用过React的应该都知道,在React中,一个组件中要读取当前状态需要访问this.state,但是更新状态却需要使用this.setState,不是直接在this.state上修改,就比如这样:
//读取状态
const count = this.state.count;
//更新状态
this.setState({count: count + 1});
//无意义的修改
this.state.count = count + 1;
同步和异步
开发中我们并不能直接通过修改state的值来让界面发生更新:
因为我们修改了state之后,希望React根据最新的State来重新渲染界面,但是这种方式的修改React并不知道数据发生了变化;
React并没有实现类似于Vue2中的Object.defineProperty或者Vue3中的Proxy的方式来监听数据的变化;
我们必须通过setState来告知React数据已经发生了变化;
疑惑:在组件中并没有实现setState的方法,为什么可以调用呢?
原因很简单,setState方法是从Component中继承过来的
(1)setState异步更新
setState的更新是异步的?
changeText() {
this.setState({
message: "你好啊,李银河"
})
console.log(this.state.message); // Hello World
}
最终打印结果是Hello World;
可见setState是异步的操作,我们并不能在执行完setState之后立马拿到最新的state的结果
为什么setState设计为异步呢?
setState设计为异步其实之前在GitHub上也有很多的讨论;
React核心成员(Redux的作者)Dan Abramov也有对应的回复,有兴趣的同学可以参考一下;
https://github.com/facebook/react/issues/11527#issuecomment-360199710;
我对其回答做一个简单的总结:
setState设计为异步,可以显著的提升性能;
如果每次调用 setState都进行一次更新,那么意味着render函数会被频繁调用,界面重新渲染,这样效率是很低的;
最好的办法应该是获取到多个更新,之后进行批量更新;
如果同步更新了state,但是还没有执行render函数,那么state和props不能保持同步;
state和props不能保持一致性,会在开发中产生很多的问题;
(2)如何获取异步的结果
那么如何可以获取到更新后的值呢?
方式一:setState的回调
setState接受两个参数:第二个参数是一个回调函数,这个回调函数会在更新后会执行;
格式如下:setState(partialState, callback)
this.setState({
message: "你好啊,李银河"
}, () => {
console.log(this.state.message);
})
方式二:在生命周期函数内获取
componentDidUpdate() {
// 方式二: 获取异步更新的state
console.log(this.state.message);
}
(3)setState一定是异步吗?
其实分成两种情况:
在组件生命周期或React合成事件中,setState是异步;
在setTimeout或者原生dom事件中,setState是同步;
验证一:在setTimeout中的更新:
changeText() {
// 情况一: 将setState放入到定时器中
setTimeout(() => {
this.setState({
message: "你好啊,李银河"
})
console.log(this.state.message); // 你好啊,李银河
}, 0);
}
验证二:原生DOM事件:
componentDidMount() {
document.getElementById("btn").addEventListener("click", (e) => {
this.setState({
message: "你好啊,李银河"
})
console.log(this.state.message);
})
// this.setState({
// message: "你好啊,李银河"
// })
// console.log(this.state.message);
}
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。