state
setState
更新状态setState 的调用方式相当于 Object.assign(之前的state,新的state)
然而,其实 setState 改变数据这个行为,有时候可能是异步的,也就是说,如果要立即获取改变后的状态,可能做不到
如下的代码的大致过程:
无论点击多少次,打印的始终是上一次 n 的值(不同步)
export default class Test extends Component {
state = {
n: 0
}
handleClick=()=>{
this.setState({
n:this.state.n + 1
})
console.log(this.state.n) // 上面调用了 setState 后,立即打印 n : 依然等于 0
}
render() {
console.log('render')
return (
<div>
<h1>{this.state.n}</h1>
<button onClick={this.handleClick}>add</button>
</div>
)
}
}
问题的根源,因为还没读过源码,暂且讲不清楚
不过根据下面的代码,可以推测一二:
constructor
中添加了一定时器这时,每次都是打印改变后的状态 n(同步)
export default class Test extends Component {
state = {
n: 0
}
constructor(props){
super(props)
setInterval(()=>{
this.setState({
n:this.state.n + 1
})
console.log(this.state.n)
},1000)
}
render() {
console.log('render')
return (
<div>
<h1>{this.state.n}</h1>
</div>
)
}
}
两相比较,得出初步结论: 在HTML上使用的处理函数调用的,是异步的;其他都是同步的
这里说的只是html处理函数调用的 setState
(其他的调用方式都是同步改变的)
setState 方法的第二个参数是一个回调函数,该函数会在所有异步改变状态的 setState 执行完之后被调用
如下的情况(例子仅仅说明问题,没有实际意义):
export default class Test extends Component {
state = {
n: 0
}
handleClick=()=>{
this.setState({
n:this.state.n + 1
},()=>{
console.log('n: ',this.state.n)
})
}
render() {
console.log('render')
return (
<div>
<h1>{this.state.n}</h1>
<button onClick={this.handleClick}>add</button>
</div>
)
}
}
回调函数中打印的this.state.n
是改变后的状态数据
当需要连续改变多次状态,并且使用多次改变状态之后的值时,如果使用上面的方法会造成嵌套,而且导致组件渲染多次,不太好
可以给 setState 传递一个函数(同样的,例子仅仅说明问题,没有实际意义):
cur
是当前状态,返回值是一个对象,与之前的状态 Object.assign
export default class Test extends Component {
state = {
n: 0
}
handleClick = () => {
this.setState(cur => ({
n: cur.n + 1
}))
this.setState(cur => ({
n: cur.n + 1
}))
this.setState(cur => ({
n: cur.n + 1
}))
}
render() {
console.log('render')
return (
<div>
<h1>{this.state.n}</h1>
<button onClick={this.handleClick}>add</button>
</div>
)
}
}
onClick
onMouseEnter
onMouseDown
等等,都是异步;其他方式是同步的