1.setState更新状态的两种写法:
(1). setState(stateChange, [callback])------对象式的setState
1.stateChange为状态改变对象(该对象可以体现出状态的更改)
2.callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用
(2). setState(updater, [callback])------函数式的setState
1.updater为返回stateChange对象的函数。
2.updater可以接收到state和props。
4.callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。
总结:
1.对象式的setState是函数式的setState的简写方式(语法糖)
2.使用原则:
(1).如果新状态不依赖于原状态 ===> 使用对象方式 例如:
this.setState({msg:"我是修改后的值"})
(2).如果新状态依赖于原状态 ===> 使用函数方式
this.setState(state => ({count:state.count+1}))
(3).如果需要在setState()执行后获取最新的状态数据,
要在第二个callback函数中读取
setState 并不是单纯同步/异步的,它的表现会因调用的场景不同而不同:在React钩子函数及合成事件中,它表现为异步;而在setTimeOut,setInterval等函数中,包括在DOM原生事件中,它都表现为同步。这种差异,本质上是由React事务机制和批量更新机制的工作方式来决定的。
在源码中通过isBatchingUpdates 来判断setState是先存进state队列还是直接更新,如果值为true则执行异步操作,为false则直接更新。
那什么情况下 isBatchingUpdates 会为 true 呢?
· 在 React 可以控制的地方,isBatchingUpdates就为 true,比如在 React 生命周期事件和合成事件中,都会走合并操作,延迟更新的策略。
· 在 React 无法控制的地方,比如原生事件,具体就是在 addEventListener 、setTimeout、setInterval 等事件中,就只能同步更新。
一般认为,做异步设计是为了性能优化、减少渲染次数,React 团队还补充了两点:
· 保持内部一致性。如果将 state 改为同步更新,那尽管 state 的更新是同步的,但是 props不是。 · 启用并发更新,完成异步渲染。
3.如何将同步获取setState处理过后的值呢?
1)可以在回调函数中获取setState处理过后的值。
add = ()=>{
// this.setState(state => ({count:state.count+1}))
this.setState((preState)=>{
return {count:++preState.count}
},()=>{//此时setState异步执行
console.log(this.state.count)//1
})
}
2) 可以使用es6中的async await 来实现同步。
add = async ()=>{
await this.setState(state => ({count:state.count+1}))
console.log(this.state.count)//1
}
add = ()=>{
setTimeout(()=>{
this.setState(state => ({count:state.count+1}))
console.log(this.state.count)//1
},0)
}
注意:如果强行使用同步,就会每次改变状态都会重新render渲染,这样性能就会降低。