setState是异步处理函数吗?
import React, {Component} from 'react';
class Count extends Component {
constructor(props) {
super(props);
this.state = {count: 0};
}
handle(e) {
this.setState({count: this.state.count + 1});
}
render() {
return (
<div>
<span>{this.state.count}</span>
<input type="button" value="Click me" onClick={this.handle.bind(this)}/>
</div>
)
}
}
export default Count;
我们在setState下面加了一个console,通过控制台可以发现,每次打印的值并不是当前输入的值,而是上一次输入的值,这是怎么回事呢?
在setState中,这是一个异步处理的函数,并不是同步的,console在setState后立刻执行了,所以这时候状态还没有真正变更完,所以这里取到的状态仍旧是更新前的
如何立即获取设置后的state值
1.回调函数
setState函数的第二个参数是callback,所以
this.setState({count: this.state.count + 1}, function () {
console.log(this.state.name);//立即获取设置后的值
});
2.传入状态计算函数
除了使用回调韩式的方式监听状态更新结果之外,react还允许我们传入某个状态计算函数而不是对象作为第一个参数。状态计算函数能够为我们提供可依赖的组件的state与props值,即会自动的将我们的状态更新操作添加到队列中并等待前面的更新完毕后传入更新的状态值:
/*用法*/
this.setState(function(prevState, props){
return {需要改变的state的名称: 改变之后的state的值}
});
如果要实现点击一次按钮count连加两次,直观的写法我们可以连续调用两次setState函数,这边的用法可能看起来有点怪异,不过更多的是为了说明异步更新带来的数据不可预测问题。
handle(){
this.setState({count : this.state.count + 1})
this.setState({count : this.state.count + 1})
}
上述代码的效果是每次点击之后计数值只会加1,实际上第二个setState并没有等待第一个setState执行完毕就开始执行了,因此其依赖的当前计数值完全是错的。不过这里我们使用状态计算函数来保证同步性:
handle(){
this.setState((prevState, props) => ({
count: prevState.count + 1
}));
this.setState((prevState, props) => ({
count: prevState.count + 1
}));
}
这里的第二个setState传入的prevState值就是第一个setState执行完毕之后的计数值,也顺利保证了连续自增两次。
带来好处
- 批量操作
Instead of:
this.setState({foo: "one"}, () => {
this.setState({bar: "two"});
});
just do this:
this.setState({
foo: "one",
bar: "two"
});
- 因为每次setState后state发生改变触发页面re-render,倘若是同步操作可能引起浏览器无响应,而异步操作,提高了UI体验和性能
网友评论