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渲染,這樣性能就會降低。