react修改狀態(tài)是不能直接修改的,需要使用setState來(lái)進(jìn)行狀態(tài)的修改,但是setState的使用會(huì)存在一些問(wèn)題。覺(jué)得有必要在此做一下總結(jié)。。。。
setState()不是立刻更新組件。其可能是批處理或推遲更新。這使得在調(diào)用setState()后立刻讀取this.state的一個(gè)潛在陷阱。
就像這樣:
incrementCount() {
this.setState({count: this.state.count + 1});
}
handleSomething() {
this.incrementCount();
this.incrementCount();
this.incrementCount();
}
調(diào)用了3次incrementCount方法, 期望this.state.count的值是3, 但最后卻是1
本質(zhì)上setState修改state的值是通過(guò)淺合并把新的值合并到state的對(duì)象上,如果多次修改,react會(huì)進(jìn)行批次處理
類(lèi)似于:
Object.assign(
previousState,
{count: state.count + 1},
{count: state.count + 1},
{count: state.count + 1},
)
之后的調(diào)用在同一周期中將會(huì)重寫(xiě)之前調(diào)用的值,因此數(shù)量?jī)H會(huì)被加一。若之后的狀態(tài)依賴于之前的狀態(tài),
解決這個(gè)問(wèn)題的方式:
componentDidUpdate或一個(gè)setState回調(diào)(setState(updater, callback))
- 當(dāng)中的每個(gè)方法都會(huì)保證在更新被應(yīng)用之后觸發(fā)
- updater函數(shù)接收到的prevState 和 props保證都是最新的
incrementCount() {
this.setState((state) => {
return {count: state.count + 1}
});
}
handleSomething() {
this.incrementCount();
this.incrementCount();
this.incrementCount();
}
setState什么時(shí)候會(huì)異步更新
setState的執(zhí)行流程:
this.setState(newState)
==>
newState存入pending隊(duì)列
==>
判斷是否處于batch update
==>
如果是的話就保存組件月dirtyComponents中,
如果不是的話就遍歷所有的dirtyComponents,調(diào)用updateComponent,更新pending state or props
在 React 的 setState 函數(shù)實(shí)現(xiàn)中,會(huì)根據(jù)一個(gè)變量 isBatchingUpdates 判斷是直接更新 this.state 還是放到隊(duì)列中回頭再說(shuō),
而 isBatchingUpdates 默認(rèn)是 false,也就表示 setState 會(huì)同步更新 this.state,
但是,有一個(gè)函數(shù) batchedUpdates,這個(gè)函數(shù)會(huì)把 isBatchingUpdates 修改為 true,
而當(dāng) React 在調(diào)用事件處理函數(shù)之前就會(huì)調(diào)用這個(gè) batchedUpdates,造成的后果,就是由 React 控制的事件處理過(guò)程 setState 不會(huì)同步更新 this.state。
- setState會(huì)導(dǎo)致re-rederning, 而re-rederning的代價(jià)是昂貴的, 所以他們會(huì)盡可能的把多次操作合并成一次提交。
- 因?yàn)楫?dāng)傳入的是一個(gè)函數(shù)時(shí),state讀取的是pending隊(duì)列中state的值
setState什么時(shí)候會(huì)異步更新, 什么時(shí)候會(huì)同步更新
React是根據(jù)isBatchingUpdates來(lái)合并更新的, 那么當(dāng)調(diào)用setState的方法或者函數(shù)不是由React控制的話, setState自然就是同步更新了。
- 如componentDidMount等生命周期以及React的事件即為異步更新,這里不顯示具體代碼。
- 如自定義的瀏覽器事件,setTimeout,setInterval等脫離React控制的方法, 即為同步更新