為什么setState沒有立即執(zhí)行

setState()沒有立即生效這個(gè)問題虏冻,在做項(xiàng)目的時(shí)候不止一次遇到肤粱。每次遇到的時(shí)候,解決辦法都是現(xiàn)成的厨相,并沒有細(xì)細(xì)的深入探究為什么在調(diào)用setState的時(shí)候this.state在一定幾率下沒有立即生效的原因领曼。這次在做****的時(shí)候鸥鹉,又遇到了這個(gè)問題,決定詳細(xì)探究一下悯森,查一查資料宋舷,并做一個(gè)記錄。

首先瓢姻,看一下react官方對setState這個(gè)API的定義祝蝠。在react的官方文檔里這樣描述setState()這個(gè)API:

setState(object nextState[, function callback])

合并 nextState 和當(dāng)前 state。這是在事件處理函數(shù)中和請求回調(diào)函數(shù)中觸發(fā) UI 更新的主要方法幻碱。另外绎狭,也支持可選的回調(diào)函數(shù),該函數(shù)在 setState 執(zhí)行完畢并且組件重新渲染完成之后調(diào)用褥傍。
同時(shí)還提出了注意點(diǎn):
setState()不會(huì)立刻改變 this.state儡嘶,而是創(chuàng)建一個(gè)即將處理的 state 事務(wù)。在調(diào)用該方法之后獲取 this.state 的值可能會(huì)得到現(xiàn)有的值恍风,而不是最新設(shè)置的值蹦狂。不保證 setState() 調(diào)用的同步性偏塞,為了提升性能看政,可能會(huì)批量執(zhí)行 state 轉(zhuǎn)變和 DOM 渲染。
所以娶牌,一般情況下锦募,我們想要確保在state合并完成之后執(zhí)行方法摆屯,就會(huì)把需要執(zhí)行的內(nèi)容寫在回調(diào)函數(shù)內(nèi)。

當(dāng)然糠亩,不管怎樣還是要代碼說話,

class Example extends React.Component {
  constructor(){
  super();
  this.state = {
     val:0
  };
}
componentDidMount() {
   this.setState({val:this.state.val+1});
   console.log(this.state.val);//第1次 0
   this.setState({val:this.state.val+1});
   console.log(this.state.val);//第2次 0
   setTimeout(() => {
      this.setState({val:this.state.val+1});
      console.log(this.state.val);//第3次 2
      this.setState({val:this.state.val+1});
      console.log(this.state.val);//第4次 3
   },0)
 }
}

這四次輸出的val分別是0虐骑,0,2赎线,3廷没,是不是有點(diǎn)出乎意料。在第一次和第二次輸出的時(shí)候setState()到底干啥去了垂寥。

眾所周知腕柜,react的源碼的體量還是有點(diǎn)兒大的。但是為什么react的執(zhí)行會(huì)如此迅速矫废。根據(jù)核心開發(fā)者之一 Pete Hunt的闡述,其中有一個(gè)原因就是每一個(gè)組件都有其完整的生命周期砰蠢,這些生命周期方法保證所有對 DOM 的修改都是批量更新的(batch update)蓖扑。

為了搞明白setState之后發(fā)生了什么。我大致梳理了一下源碼(我看的源碼版本是0.14.7),將代碼的重點(diǎn)整理如下圖:

首先台舱,在我們調(diào)用 setState 方法后律杠,要明確的一點(diǎn)是 state 是不一定會(huì)立即更新的潭流。因?yàn)榇藭r(shí)會(huì)調(diào)用一個(gè) enqueueSetState 方法,傳入要更新的 state 柜去。如果存在 callback 的話灰嫉,也會(huì)調(diào)用 enqueueCallback 的方法。 在 enqueueSetState 方法中嗓奢,會(huì)將新的 state 暫時(shí)存入一個(gè)臨時(shí)數(shù)組 _pendingStateQueue 中讼撒。然后再調(diào)用 enqueueUpdate 方法。在 enqueueUpdate 方法中就出現(xiàn)了傳說中的batchingStrategy 批處理策略股耽。 在這里用 isBatchingUpdates 這個(gè)標(biāo)志來標(biāo)記是否處于一次 batchupdates 中根盒,如果不處于一次 batchupdates,那么就會(huì)執(zhí)行 update物蝙,否則炎滞,就會(huì)將當(dāng)前 component 存入 dirtyComponents 數(shù)組中。

根據(jù)以上的分析诬乞,就能知道册赛,為什么在一次 setState 執(zhí)行的時(shí)候,state 沒有立即更新震嫉。

同樣的森瘪,為什么最上面示例代碼的執(zhí)行結(jié)果是0,0责掏,2柜砾,3,是因?yàn)閮纱沃苯訄?zhí)行的 setState 和在 setTimeout 中的 setState 的調(diào)用棧不一樣换衬。直接執(zhí)行 setState 的時(shí)候痰驱,此時(shí)正處于一次 batchupdates,所以并不會(huì)立即更新瞳浦,而是暫存担映,等同一批的 state 都合并之后,再一次性更新叫潦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蝇完,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子矗蕊,更是在濱河造成了極大的恐慌短蜕,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件傻咖,死亡現(xiàn)場離奇詭異朋魔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)卿操,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門警检,熙熙樓的掌柜王于貴愁眉苦臉地迎上來孙援,“玉大人,你說我怎么就攤上這事扇雕⊥厥郏” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵镶奉,是天一觀的道長础淤。 經(jīng)常有香客問我,道長腮鞍,這世上最難降的妖魔是什么值骇? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮移国,結(jié)果婚禮上吱瘩,老公的妹妹穿的比我還像新娘。我一直安慰自己迹缀,他們只是感情好使碾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著祝懂,像睡著了一般票摇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上砚蓬,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天矢门,我揣著相機(jī)與錄音,去河邊找鬼灰蛙。 笑死祟剔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的摩梧。 我是一名探鬼主播物延,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼仅父!你這毒婦竟也來了叛薯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤笙纤,失蹤者是張志新(化名)和其女友劉穎耗溜,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體省容,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡抖拴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蓉冈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片城舞。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖寞酿,靈堂內(nèi)的尸體忽然破棺而出家夺,到底是詐尸還是另有隱情,我是刑警寧澤伐弹,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布拉馋,位于F島的核電站,受9級(jí)特大地震影響惨好,放射性物質(zhì)發(fā)生泄漏煌茴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一日川、第九天 我趴在偏房一處隱蔽的房頂上張望蔓腐。 院中可真熱鬧,春花似錦龄句、人聲如沸回论。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽傀蓉。三九已至,卻和暖如春职抡,著一層夾襖步出監(jiān)牢的瞬間葬燎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工缚甩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谱净,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓蹄胰,卻偏偏與公主長得像岳遥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子裕寨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容