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渲染,这样性能就会降低。
