為了更近一步理解平常使用的 useState, useEffect, memo...等機制的運作,我嘗試下載了 React 的原始碼,沒想到初次見面就讓人手足無措。幸好官方提供了一些給開源貢獻者的指南,跟隨著官方的文件,可以省下不少力氣。
底下的內容會跟著 React 的文件,認識原始碼的大致架構。並且附上 IDE 的截圖,讓各位更好地想像。
packages
裡包含了所有 React 專案內的 packages 的 metadata(例如:package.json
)以及 source code( src
子目錄)。
fixtures
裡面包含了幾個讓貢獻者可以使用的測試工具。
build
資料夾裡面有專案 build 出來的東西。
其他的資料夾大部分是工具相關,貢獻者通常不會需要處理到、或者遇到跟這些資料夾相關的議題。
註:有另一個名稱相似的專案 https://github.com/reactjs/reactjs.org 放的是 React 相關的文件。放 Source code 的專案則是 https://github.com/facebook/react。
(我的專案 build 不起來,所以少了其中一個資料夾。除了 build,頂層資料夾就是這些。)
React 專案使用 console.error
來表示警告,只有在開發環境中才會顯示,在正式環境中則是完全看不見。如下圖:
你還可以使用專案裡的 invariant
模組。當情境是 false 的時候,Invariant 就會被拋出。你可以把這個功能想像成在做一個斷言(assertion)。如下圖:
與上面不同的是,Invariant 在開發與正式環境中都會運行,只是在正式環境中,error message 會被自動的替換成 error code 來避免對 byte size 的負面影響。
React 是一個 monorepo。在同一個 repo 中管理多的模組的好處在於,方便統一管理 depencency、版號、流程,以及因為東西都放在一起,大規模的重構時會更容易,這些模組間的改變也可以互相協調。
React 的核心包含所有 top-level 的 API,僅僅包含那些定義元件所必須的 API,不包含演算法或者任何 platform-specific 的 code。這些 API 會被 React DOM 以及 React Native 元件二者使用。React core 的內容位於 packages/react
:底下的截圖中,可以看到一些眼熟的 export createElement
、Component
、Children
... etc。
順著 import export 的路線往下追,可以找到一些關於這些 core API 如何運作的線索。
React 運用了一個事件系統來調整原生的事件,減緩不同瀏覽器之間的差異。
即使是差異極大的 renderers 例如 React DOM 與 React Native,也會需要使用許多相同邏輯。特別是 React 使用的 reconciliation algorithm 演算法也應該要盡可能地相似,讓 declarative rendering, custom components, state, lifecycle methods, 跟 refs 的運作在不同平台上的運作前後一致。
不同的 renderers 所共有的 code,我們稱呼這個部分叫做 reconciler。當一個更新例如 setState() 被觸發的時候,reconciler 會去呼叫元件上的 render(),然後對他們進行 mount, update, unmount 這些動作。
Reconciler 聽起來太抽象嗎?請參考之前關於 reconciliation 的文章:https://ithelp.ithome.com.tw/articles/10268531/
fiber 是用來解決前一版 stack reconciler 內既有的問題,以及一些長期存在的錯誤。React 16 之後就成了預設的 reconciler。他的 source code 可以在 react-reconciler 中找到。
看完這些介紹之後,大概可以抓到如果想要理解例如 React.memo 的處理,會需要查找的資料夾有 packages/react
關於 React.memo 的內容,以及 packages/
react-reconciler` 當中,可能有對於比較 prevProps 和 nextProps 判斷機制的描寫。
https://reactjs.org/docs/codebase-overview.html
https://reactjs.org/docs/implementation-notes.html