【Under-the-hood-ReactJS-Part9】React原始碼解讀

越山發表於2018-07-04

接上文,

React流程圖:
https://bogdan-lyashenko.gith…

回到最初

在流程圖中,也許你已經注意到,setState方法可以通過幾種方式觸發,更準確的說,可以分為是否由外部引起的(也就是是否由使用者觸發)。讓我們看下如下兩個列子,第一個中,
是由滑鼠點選觸發的,第二個中,是在componentDidMount中由setTimeout方法中被觸發的。

為什麼會有這些不同呢?如果你還有印象,在之前的文章中,React對於更新的處理是批量的,也就是說,一系列更新操作會通過某種方式被收集起來,然後統一重新整理到頁面上。當滑鼠事件發生時,元件的最外層會進行處理,然後通過幾層包裝器的處理後,會開始進行批量更新操作。注意,批量更新操作的前提是確保ReactEventListener處於enabled狀態,而且,在前文提到過,在元件的掛載階段,ReactReconcileTransaction包裝器中的一個會先關閉它,以確保整個掛載過程的安全。 至於setTimeout中的呼叫,則是在將元件放入dirtyComponents列表之前,React會確保事務處於開啟狀態,在這之後,關閉事務包裝器,然後將更新重新整理到頁面上。

正如你所知,React實現了合成事件,在一下原生事件包裹了一些合成語法糖。在這之後,React會將這些事件處理成常見到樣子。看下如下程式碼裡到註釋:

為了更好地開發,通過模擬真實遊覽器事件,我們可以得到更好開發工具整合過程(To help development we can get better dev tool integration by simulating a real browser event’)

var fakeNode = document.createElement(`react`);

ReactErrorUtils.invokeGuardedCallback = function (name, func, a) {
      var boundFunc = func.bind(null, a);
      var evtType = `react-` + name;

      fakeNode.addEventListener(evtType, boundFunc, false);

      var evt = document.createEvent(`Event`);
      evt.initEvent(evtType, false, false);

      fakeNode.dispatchEvent(evt);
      fakeNode.removeEventListener(evtType, boundFunc, false);
};

回到我們的更新流程,我們在這裡總結下大概的步驟:
1 呼叫setState方法
2 如果批量事務未處於開啟狀態,則開啟該事務
3 將受影響元件新增到dirtyComponents列表裡
4 通過呼叫ReactUpdates.flushBatchedUpdates方法關閉事務,也就意味著開始對dirtyComponents列表進行處理。

(未完待續)

相關文章