Skip to content

react的setState机制

什么场景下,setState会同步更新

同步更新

如果setState在以下场景里调用多次

  • addEventListener事件回调里
js
window.addEventListener('click',() => {
    this.setState({
        a: 1
    })
    this.setState({
        b: 2
    })
})
  • setTimeoutsetIntervalpromise回调里
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,然后再重新渲染一次。第三个setStatecount变成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

苏ICP备20040768号