一、setState不全是同步的!
假设在某个功能中需要连续调用setState改变某个状态,此时我们想的是每次更改都在上一步的基础上进一步更改。然鹅如果这样写(如下代码)是不能实现目的的。
import React, { Component } from 'react'
export default class Comp extends Component {
state = {
n: 0 // 将n的初始值设置为0
}
handleClick = () => {
// 连续三次调用,每次都是在原来的n上+1,最后输出会不会是3呢?
this.setState({
n: this.state.n + 1
});
this.setState({
n: this.state.n + 1
});
this.setState({
n: this.state.n + 1
});
console.log(this.state.n); // 输出
}
render() {
return (
<div>
<h1>
{this.state.n}
</h1>
// 通过一个按钮调用函数
<button onClick={this.handleClick}>+</button>
</div>
)
}
}
然而可以惊奇的发现,界面上显示的是1,控制台打印0
得出结论
- 界面上显示1说明每一次的setState都是在初始值0上进行加1的,且后面的覆盖前面的
- 控制台输出0说明执行到console语句的时候state值还没有改变
- 综上,setState存在异步改变state值的情况
二、建议
- setState存在异步更改的情况,但是也有同步的情况,开发中将setState一律视为异步方便得多(省事)
- 上面只是说明了原因,并没有解决需求,如果碰上需要连续改变、在上一次改变基础上接着改变state的需求,可以参考setState的其他参数
三、setState的其他参数
setState是一个函数,通常我们都是只传递一个对象参数对state进行改变,其实setState还可以传另外两个参数:
this.setState({
n: this.state.n + 1
}, ()=>{
console.log(this.state.n); // 第二个参数传一个回调函数
});
回调函数中可以获取到更改之后的值,众所周知异步的方法大多数都有回调函数的形式获取后续结果,不在赘述。但是如果多次在回调中多次调用setState就会形成这样的代码:
this.setState({
n: this.state.n + 1
}, ()=>{
this.setState({
n: this.state.n + 1
}, ()=>{
this.setState({
n: this.state.n + 1
}, ()=>{
this.setState({
n: this.state.n + 1
}, ()=>{
console.log(this.state.n);
});
// 、、、、、、、
});
});
});
是否有种地狱般深陷其中的感觉……
因此还可以传递另外一种形式的参数:
this.setState((cur)=>{
// 参数cur是当前的state对象
console.log(cur);
return {
n: cur.n + 1
}
})
this.setState((cur)=>{
console.log(cur);
return {
n: cur.n + 1
}
})
this.setState((cur)=>{
console.log(cur);
return {
n: cur.n + 1
}
})
通过传递一个函数给setState作为参数,这个参数的cur是当前的state对象,而且是实时更新的,因此可以通过这个参数获取最新的state来进行后续的数据操作,通过函数的return更新state。