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