react setState 之同步异步
问题来源:
在react组件中,每次修改state中的对象后接下来去取修改后的值,有时取到的值是修改前的,有时是修改后的,那setState是同步的还是异步的呢?为什么呢?
讨论1
本次研究就用代码实践来总结体会,找寻答案
import React from "react"
class test extends React.Component {
constructor(props) {
this.state = {
num:0}}
componentDidMount() {
this.setState({num: 1, }, (state) => {
console.log(this.state.num,"setState的回调函数中")
});
console.log(this.state.num,"打印")
}
render() {
console.log(this.state.num,"num变化了")
return (
<div>
<button onClick ={this.handleClick}>点击</button>
</div>
) }}
export default test
表明在react的生命函数中进行setState是异步的,在生命周期函数中,数据发生改变时,并不能马上得到改变后的值,上面的‘num变化了’一次更新打印了2次,是因为在react中的use strict 严格模式,为了更好的发现程序中的问题,运行了两次。第十行代码执行在dom刷新(每一次state重的数据发生改变时都会出发dom更新,但是因为效能原因,react的数据会一批一批的进行更新,而不是每次更新数据都会进行dom更新)之前,为了在数据更新后就使用更新后的值可以借助 this.setState({num: 1, },cb) 中的cb,利用cb中的取值,我们可以发现在dom进行更新后,取到值,也就是可以暂时得出,
结论1
在生命周期函数中,借助 this.setState({num: 1, },cb) 中的cb可以在dom更新后取到更新后的值。
讨论2
class test extends React.Component {
constructor(props) {
super(props);
this.state = {
num:0,
count:0
};
}
componentDidMount() {
setTimeout(() => {
this.setState({count: 5})
console.log(this.state.count, "定时器")
}, 3000)
new Promise((resolve,reject)=>{
setTimeout(()=>{
this.setState({count:6})
resolve()
},100)
}).then(()=>{
console.log(this.state.count,"primise中")
})
document.getElementById("yuansheng").addEventListener("click", this.handleClick2);
}
handleClick2 = () =>{
console.log("点击了原生")
this.setState({count: 1})
console.log(this.state.count)
}
handleClick = () => {
console.log("合成点击")
this.setState({count: 2})
console.log(this.state.count)
}
render() {
return (
<div>
<button onClick ={this.handleClick}>点击</button>
<div id="yuansheng">点击2div</div>
</div>)}}
export default test
结论2
从上面的运行结果可以看出在定时器和promise这种异步操作中setState可以在代码更新后取到,另外在合成点击(在react中,开发者为了兼容各个平台及其他优点,对原生的事件进行了封装,成为合成事件),并不能立马得到改变后的数据,在利用原生js绑定的原生事件就可以及时的得到改变后的数据。
总结
于是我们可以得到以下结论:
在生命周期函数,合成函数中,不能立马拿到数据原因是,console.log在数据发生改变前执行,为什么发生改变前执行,因为diff算法,虚拟dom一批一批的更新视图层,在执行顺序是,对数据进行setState -> console.log ->算法判断是否更新 -> 数据更新 -> dom更新
而promise,回调函数,原生函数,定时器 这些不受这个算法的影响,它是单独更新视图,不参与他们的一批一批的更新,所以说可以直接取到值
更多前端资料请关注微信公众号:前端从入门到SP
扫码可关注