1. setState 是同步還是異步?
我的回答是執(zhí)行過程代碼同步的,只是合成事件和鉤子函數(shù)的調(diào)用順序在更新之前,導(dǎo)致在合成事件和鉤子函數(shù)中沒法立馬拿到更新后的值,形式了所謂的“異步”,所以表現(xiàn)出來有時(shí)是同步,有時(shí)是“異步”。
2. 何時(shí)是同步,何時(shí)是異步呢?
只在合成事件和鉤子函數(shù)中是“異步”的,在原生事件和 setTimeout/setInterval等原生 API 中都是同步的。簡(jiǎn)單的可以理解為被 React 控制的函數(shù)里面就會(huì)表現(xiàn)出“異步”,反之表現(xiàn)為同步。
3. 那為什么會(huì)出現(xiàn)異步的情況呢?
為了做性能優(yōu)化,將 state 的更新延緩到最后批量合并再去渲染對(duì)于應(yīng)用的性能優(yōu)化是有極大好處的,如果每次的狀態(tài)改變都去重新渲染真實(shí) dom,那么它將帶來巨大的性能消耗。
4. 那如何在表現(xiàn)出異步的函數(shù)里可以準(zhǔn)確拿到更新后的 state 呢?
通過第二個(gè)參數(shù) setState(partialState, callback) 中的 callback 拿到更新后的結(jié)果。
或者可以通過給 setState 傳遞函數(shù)來表現(xiàn)出同步的情況:
this.setState((state) => {
return { val: newVal }
})
5. 那表現(xiàn)出異步的原理是怎么樣的呢?
源碼可參考<React-setState原理>
這里還是用最簡(jiǎn)單的語言讓你理解:在 React 的 setState 函數(shù)實(shí)現(xiàn)中,會(huì)根據(jù) isBatchingUpdates(默認(rèn)是 false) 變量判斷是否直接更新 this.state 還是放到隊(duì)列中稍后更新。然后有一個(gè) batchedUpdate 函數(shù),可以修改 isBatchingUpdates 為 true,當(dāng) React 調(diào)用事件處理函數(shù)之前,或者生命周期函數(shù)之前就會(huì)調(diào)用 batchedUpdate 函數(shù),這樣的話,setState 就不會(huì)同步更新 this.state,而是放到更新隊(duì)列里面后續(xù)更新。
這樣你就可以理解為什么原生事件和 setTimeout/setinterval 里面調(diào)用 this.state 會(huì)同步更新了吧,因?yàn)橥ㄟ^這些函數(shù)調(diào)用的 React 沒辦法去調(diào)用 batchedUpdate 函數(shù)將 isBatchingUpdates 設(shè)置為 true,那么這個(gè)時(shí)候 setState 的時(shí)候默認(rèn)就是 false,那么就會(huì)同步更新。