React setState合併和批量處理

xiaowoniu發表於2020-03-14

一、State的更新什麼時候是同步,什麼時候是非同步

 正如我們所知,react中使用setState更新state,而state的更新大多數情況下是非同步的,但是有些情況卻是同步的。
在React中,如果是由React引發的事件處理(比如通過onClick引發的事件處理),呼叫setState不會同步更新this.state,除此之外的setState呼叫會同步執行this.state。所謂“除此之外”,指的是繞過React通過addEventListener直接新增的事件處理函式,還有通過setTimeout/setInterval產生的非同步呼叫。

二、為什麼是非同步

 如果setState是同步更新state,而state的更新又會觸發元件的重新渲染,那麼每次setState都會渲染元件,這對效能是很大的消耗。所以react進行了setState的合併和批量延遲更新,正如官網所述:

React setState合併和批量處理

三、如何實現setState的合併和批量延遲

 檢視react原始碼發現,程式碼中有一個變數鎖isBatchingUpdates,isBatchingUpdates表示是否進行批量更新,初始化時預設為false,batchedUpdates方法會將isBatchingUpdates設為true

var ReactDefaultBatchingStrategy = {
  isBatchingUpdates: false,

  batchedUpdates: function(callback, a, b, c, d, e) {
    var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;

    ReactDefaultBatchingStrategy.isBatchingUpdates = true;

    if (alreadyBatchingUpdates) {
      return callback(a, b, c, d, e);
    } else {
      return transaction.perform(callback, null, a, b, c, d, e);
    }
  },
};

module.exports = ReactDefaultBatchingStrategy;

複製程式碼

 為了合併setState,我們需要一個佇列來儲存每次setState的資料,然後在一段時間後,清空這個佇列並渲染元件,這個佇列就是dirtyComponents。當isBatchingUpdates為true時,將會執行 dirtyComponents.push(component); 將元件push到dirtyComponents佇列。
 呼叫setState()時,其實已經呼叫了ReactUpdates.batchedUpdates,此時isBatchingUpdates便是true。

if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }
dirtyComponents.push(component);
複製程式碼

 至此,setState實現了合併和批量處理。


參考:
setState何時同步更新狀態
從零開始實現一個React(四):非同步的setState
React - setState原始碼分析(小白可讀)

相關文章