鍍金池/ 問答/HTML/ react中放到定時器中的多個setState為什么不會合并再執(zhí)行?

react中放到定時器中的多個setState為什么不會合并再執(zhí)行?

描述

setState通過一個隊(duì)列機(jī)制實(shí)現(xiàn)state更新,當(dāng)執(zhí)行setState時,會將需要更新的state 合并后放入狀態(tài)隊(duì)列,而不會立刻更新this.state,隊(duì)列機(jī)制可以高效地批量更新 state。

實(shí)例:

constructor(){
    this.state={
        val:0,
    }
}
componentDidMount(){
    this.setState({val:this.state.val+1});
    console.log(this.state.val);
    
    this.setState({val:this.state.val+1});
    console.log(this.state.val);
    
    setTimeout(()=>{
    this.setState({val:this.state.val+1});
    console.log(this.state.val);
    
    this.setState({val:this.state.val+1});
    console.log(this.state.val);
    },0);
}
結(jié)果:0,0,2,3

問題描述

為什么不是0,0,2,2?

  • 0,0,2能明白,前兩次還在批量更新中,所以先合并setState,并且是在下次render才能得到結(jié)果。
  • 當(dāng)執(zhí)行setTimeout時,第一個setState雖然這時批量更新為false,但是為什么這個setState沒把組件狀態(tài)變成批量更新狀態(tài)?從而觸發(fā)批量更新事務(wù),使得定時器中的兩次setState進(jìn)行合并?

很是疑惑,感覺和講解的setState機(jī)制矛盾,但是結(jié)果卻是是分開執(zhí)行的。

回答
編輯回答
故林
  1. setState 只在合成事件和鉤子函數(shù)中是“異步”的,在原生事件和 setTimeout 中都是同步的。
  2. setState的“異步”并不是說內(nèi)部由異步代碼實(shí)現(xiàn),其實(shí)本身執(zhí)行的過程和代碼都是同步的,只是合成事件和鉤子函數(shù)的調(diào)用順序在更新之前,導(dǎo)致在合成事件和鉤子函數(shù)中沒法立馬拿到更新后的值,形式了所謂的“異步”,當(dāng)然可以通過第二個參數(shù) setState(partialState, callback) 中的callback拿到更新后的結(jié)果。
  3. setState 的批量更新優(yōu)化也是建立在“異步”(合成事件、鉤子函數(shù))之上的,在原生事件和setTimeout 中不會批量更新,在“異步”中如果對同一個值進(jìn)行多次 setStatesetState 的批量更新策略會對其進(jìn)行覆蓋,取最后一次的執(zhí)行,如果是同時 setState 多個不同的值,在更新時會對其進(jìn)行合并批量更新。
2017年2月18日 21:01