研究 React 應用程序的內部運行機制要找到切入點
前言
做為一名 React 開發者,你是否思考過為什么我們在開發 React 程序時并未直接(使用 JavaScript API)操作 DOM 卻能更新 DOM,以及當組件中的 this.setState( ... )
操作被觸發后 React 內部到底做了哪些工作?本節將會介紹研究 React 內部運行機制的切入點以及整體研究思路。
如何研究 React 內部運行機制
我們想要知道 React 的內部運行機制,實際上就是要探索 React 如何將組件映射屏幕,以及組件中的 state 和 prop 發生了變化之后 React 如何將這些「變化」更新到屏幕。
想要搞清楚上面的兩個問題,我們需要對 React 應用程序的首次渲染過程和更新渲染過程有整體的認知。那么,應用程序的首次渲染和更新渲染兩個過程中 React 內部要做的工作有什么相同點與不同點呢?
圖 1.1.1 React 應用程序的兩種渲染
應用程序首次渲染時 React 會做一些基建工作,比如 將組件轉化為元素,構建更新隊列,構建 workInProgress 對象樹以及構建 Effect list(副作用列表) 等。這些基建工作是構建 React Fiber 架構的關鍵環節。而在應用程序更新渲染時,React Fiber 架構的實體 —fiberRoot 對象已經存在于內存中,此時,React 更加關心的是 計算出 Fiber 架構中各個結點的前后變化,并將【變化部分】更新到屏幕。
現在,我們對上面圖中的兩個渲染過程中的關鍵環節用流程圖表示,見圖 1.1.2。
圖 1.1.2 React 應用程序的兩種渲染流程
React 應用程序首次渲染時的關鍵環節解析
- 構建 fiberRoot 對象(
FiberRootNode
構造函數的實例),fiberRoot 對象是整個 Fiber 架構的根結點對象。 - 將更新加入到更新隊列,此時的更新內容為應用程序的根組件。
- 應用程序進入 render 階段,在該階段 React 的主要工作是構建 workInProgress 樹(一顆 Fiber 樹)。
- 構建 workInProgress 樹的過程中會做一些重要的工作,如為結點標記 effectTag,對結點進行 diff 處理,收集 Effect List(副作用列表),調用生命周期函數等。
- 當收集好 Effect List 后則進入 commit 階段,在該階段 React 主要工作就是將 Effect List 更新到屏幕,然后渲染結束。
React 應用程序更新渲染時的關鍵環節解析
- 相對于應用程序的首次渲染,更新渲染流程的主要區別有,不再重新構建 fiberRoot 對象,因為該對象已經存在于內存中。
- 此時的更新內容一般為組件內部發生變化的
state
和props
。 - 在進入 render 階段前要進行任務調度,更新任務需要申請(檢查是否有)執行權,得到更新執行權的任務才能進行后續渲染工作。
- 此時構建 workInProgress 樹時也會盡可能的復用上一次創建的 Fiber 結點,同時對需要更新的結點標記對應的 effectTag。
- 在 commit 階段得到的 Effect List 是被標記了 effectTag 的 Fiber 結點集合(一個鏈表),其一般是 workInProgress 樹的子集。
注:上面提到的 React 在渲染過程中的工作多是抽象內容,后面我們會對其中每一項工作通過獲取真實運行狀態進行詳細分析。
研究 React 內部運行機制 — 思維導圖
圖 1.1.3 專欄學習思維導圖
小結
本文提到的有關 React Fiber 架構的相關內容以及構建 workInProgress 樹、Effect List 等內容在后面章節中會有詳細介紹?,F在我們知道,要想打開 React 應用程序內部運行機制的大門,解鎖 ReactDOM.render
函數是關鍵,因為 ReactDOM.render
函數是 React 應用程序首次渲染時的入口函數,我們需要對它有更多的了解,ReactDOM.render
函數的更多介紹見本章第二節。