this.props 和 this.state 可能是异步更新的,你不能依赖他们的值计算下一个state(状态)
- 调用setState后,setState会把要修改的状态放入一个队列中(因而 组件的state并不会立即改变);
- 之后React 会优化真正的执行时机,来优化性能,所以优化过程中有可能会将多个 setState 的状态修改合并为一次状态修改,因而state更新可能是异步的。
- 所以不要依赖当前的State,计算下个State。当真正执行状态修改时,依赖的this.state并不能保证是最新的State,因为React会把多次State的修改合并成一次,这时,this.state将还是这几次State修改前的State。
- 另外需要注意的事,同样不能依赖当前的Props计算下个状态,因为Props一般也是从父组件的State中获取,依然无法确定在组件状态更新时的值。
class App extends React.Component {
state = {
counter: 0
}
handleClick = () => {
const counter = this.state.counter;
this.setState({ counter: counter + 1 })
this.setState({ counter: counter + 1 })
this.setState({ counter: counter + 1 })
}
render() {
return (
<div>
counter is: {this.state.counter}
<button onClick={this.handleClick}>点我</button>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
每点击一下该按钮,结果会是 + 1,并不是我们意想中的 + 3
React 会把传入多个 setState的多个 Object “batch” 起来合并成一个。合并成一个就相当于把传入 setState 的多个 Object 进行 shallow merge , 像这样:
const update = {
counter: counter + 1,
counter: counter + 1,
counter: counter + 1
// 因为三行代码相同,所以会当一句话执行
}
我们可以这样修改
handleClick = () => {
this.setState((prev) => ({ counter: prev.counter + 1 })) // 注意不要直接修改原数据,如 ++counter / counter++
this.setState((prev) => ({ counter: prev.counter + 1 }))
this.setState((prev) => ({ counter: prev.counter + 1 }))
}
传入多个 setState 的多个 Object 会被 shallow Merge,而传入多个 setState 的多个 function 会被**“queue”**起来,queue 里的 function 接收到的 state(上面是 prev )都是前一个 function 操作过的 state。