react的setState机制
什么场景下,setState会同步更新
同步更新
如果setState
在以下场景里调用多次
addEventListener
事件回调里
js
window.addEventListener('click',() => {
this.setState({
a: 1
})
this.setState({
b: 2
})
})
setTimeout
、setInterval
、promise
回调里
js
setTimeout(() => {
this.setState({
a: 1
})
this.setState({
b: 2
})
},10)
那么回调里的多个setState
会同步执行。且执行多次。以上面例子为例,setState
会触发两次渲染
异步更新
如果setState
写在react元素绑定的事件回调里
则setState
会异步执行,setState
只触发一次渲染
注意: 从React18以及以上版本开始,setState
都是异步更新
且合并state
什么场景下,setState会合并state(批量更新)
合并场景
如果setState
满足同步执行,则不会合并state
js
this.state = {
count: 0,
}
setTimeout(() => {
this.setState({
count: this.state.count + 1
})
this.setState({
count: this.state.count + 1
})
this.setState({
count: this.state.count + 1
})
}, 1000)
以上代码执行后。count
显示为3。 因为此时setState
代码同步执行,所以更新顺序是第一个setState
先把count
变成1,然后渲染一次。第二个setState
先把count
变成2,然后再重新渲染一次。第三个setState
把count
变成3,触发最后一次渲染。
总结下就是会触发3次渲染,界面依次更新成1、2、3。只是界面渲染比较快,看起来是从0直接变成3
不合并场景
如果setState
满足异步执行,则会合并state
js
this.state = {
count: 0,
}
// 事件回调里
const handleClick = () => {
this.setState({
count: this.state.count + 1
})
this.setState({
count: this.state.count + 1
})
this.setState({
count: this.state.count + 1
})
}
以上代码执行后。count
显示为1。 这是因为事件里setState
传入的对象参数,会先存到队列里,比如上面例子中,队列里状态为[{count:1},{count:1},{count:1}]
,然后触发点击事件时,三个对象会进行合并,变成{count:1}
,然后再进行渲染。 从上面步骤可以看出与同步执行的setState
的区别,异步setState
只触发一次渲染,且是直接从0变成1
但是,需要注意! 如果setState
传入的是函数,此时不会合并
js
this.state = {
count: 0,
}
// 事件回调里
const handleClick = () => {
this.setState((prevState, props) => {
return {
count: prevState.count + 1
}
})
this.setState((prevState, props) => {
return {
count: prevState.count + 1
}
})
this.setState((prevState, props) => {
return {
count: prevState.count + 1
}
})
}
以上代码执行后。count
显示为3