setState,它对状态的改变,可能是异步的
如果改变状态的代码处于某个HTML元素的事件中,则其是异步的,否则是同步
最佳实践:
1.把所有的setState当做是异步的
2.永远不要信任setState调用之后的状态
3.如果需要使用改变之后的状态,需要使用回调函数(setState的第二个参数)
import React, { Component } from 'react'
export default class Comp extends Component {
state = {
n: 0
}
handleClick = () => {
this.setState({
n: this.state.n + 1
}, () => {
//状态完成改变之后触发,该回调运行在render之后
//可以拿到改变之后的值
console.log(this.state.n);
});
}
render() {
console.log("render");
return (
<div>
<h1>
{this.state.n}
</h1>
<p>
<button onClick={this.handleClick}>+</button>
</p>
</div>
)
}
}
4.如果新的状态要根据之前的状态进行运算,使用函数的方式改变状态(setState的第一个参数)
import React, { Component } from 'react'
export default class Comp extends Component {
state = {
n: 0
}
handleClick = () => {
this.setState(cur => {
//参数cur表示当前的状态
//该函数的返回结果,会混合(覆盖)掉之前的状态
//该函数是异步执行
return {
n: cur.n + 1
}
}, ()=>{
//所有状态全部更新完成,并且重新渲染后执行
console.log("state更新完成", this.state.n);
});
}
render() {
console.log("render");
return (
<div>
<h1>
{this.state.n}
</h1>
<p>
<button onClick={this.handleClick}>+</button>
</p>
</div>
)
}
}
5.React会对异步的setState进行优化,将多次的setState进行合并(将多次的状态改变完成后,再统一对state进行改变,然后触发render)
多次触发:使用setState第一个函数
this.setState(cur => ({
n: cur.n + 1
}));
this.setState(cur => ({
n: cur.n + 1
}));
this.setState(cur => ({
n: cur.n + 1
}));
到底是同步还是异步?
-
setState只在合成事件和钩子函数中是"异步"的,在原生事件和setTimeout中是同步的
-
setState的"异步"并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的"异步",当然可以通过第二个参数setState(partialState,callback)中callback拿到更新后的结果。 partialState–>局部状态
-
setState的批量更新优化也是建立在"异步"(合成事件、钩子函数)之上的,在原生事件和setTimeout中不会批量更新,在"异步"中如果对同一个值进行多次setState,setState的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时setState多个不同的值,在更新是会对其进行合并批量更新