state
state的存在是为了动态改变组件,比如根据不同的用户操作和网络请求,来重新渲染组件。
setState()是React给我们的一个API,用来改变或定义state。
setState()的批量操作(batching)
在一个事件handler函数中,不管setState()被调用多少次,他们也会在函数执行结束以后,被归结为一次重新渲染, 可以优化性能, 这个等到最后一起执行的行为被称为batching。
所以在函数内的setState()是有序的,如果要更改同一个state key,最后被调用的总会覆盖之前的。
因为batching的存在,所以这样的代码会和期待有出入。
//假设现在this.state.value = 0;
function eventHandler(){
this.setState({value:this.state.value + 1});
this.setState({value:this.state.value + 1});
this.setState({value:this.state.value + 1});
}
//最后this.state.value仍然会是1,不是3;
所以不能依赖this.state来计算未来状态。如果想实现这样的效果,应该传一个函数给setState。这个函数有两个参数,第一个为previous state,第二个为props。这里的例子和props无关,只需要第一个参数,所以要达到效果,代码是这样
// 假设 this.state = { value: 0 };
function eventHandler(){
this.setState((state) => ({ value: state.value + 1}));
this.setState((state) => ({ value: state.value + 1}));
this.setState((state) => ({ value: state.value + 1}));
}
//现在this.state.value === 3;
到这里我们得到结论,setState是异步执行的。
如React文档所说:
“setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value. There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.”
所以当更新state,然后想打印state的时候,应该使用回调。
this.setState({key: val},()=>console.log(this.state));
所以setState总是异步的,吗?
当setState()不在事件Handler函数中,如在使用ajax的时候,这种batching的异步表现又不会发生。
promise.then(() => {
// 不在事件函数中,所以setState立刻执行
this.setState({a: true}); // 重新渲染 {a: true, b: false }
this.setState({b: true}); // 重新渲染 {a: true, b: true }
});
同步异步要分情况来看:
1. React事件函数使用,像这样用最常用的形式绑定函数
constructor(props){
...
this.onClick = this.onClick.bind(this);
}
onClick(){
this.setState({key:val});
}
render(){
return(
<div>
<button onClick = {this.onClick}>Click me</button>
</div>
}
这里batching发生,异步表现,是因为这种常规情景下React “知道”什么时候退出该事件,什么时候进行Batch Update。原理可以参考这篇很简洁易懂的文章
2.其他情景,如上面的ajax情景,或这样用addEventListener绑定函数
componentDidMount(){
document.querySelector('#btn').addEventListener('click,this.onClick);
}
render(){
return(
<div>
<button id="btn">Click me</button>
</div>
}
}
脱离了React的控制,React不知道如何进行Batch Update,setState()就会是同步的。