前言
本文主要介紹一些React的設計思想和相關概念,不管是想要閱讀原始碼還是想深入瞭解React的同學看過來呀。歡迎指出錯誤,一起探討一起進步。
React閱讀系列文章
專案結構
React的相關程式碼都放在packages裡。
├── packages ------------------------------- React實現的相關程式碼
│ ├── create-subscription ------------------------- 在元件裡訂閱額外資料的工具
│ ├── events -------------------------- React事件相關
│ ├── react-art ------------------------- 畫圖相關庫
│ ├── react-dom -------------------------- ReactDom
│ ├── react-native-renderer ----------------------------- ReactNative
│ ├── react-reconciler ------------------------ React調製器
│ ├── react-scheduler ------------------------ 規劃React初始化,更新等等
│ ├── react-test-renderer ------------------------ 實驗性的React渲染器
│ ├── shared ------------------------ 公共程式碼
│ ├── simple-cache-provider ------------------------ 為React應用提供快取
複製程式碼
主要思想和設計原則
組合
React的主要特性就是各種組合而成的元件。由不同人編寫的元件可以組合使用,並且實現元件的複用。
時序安排(Scheduling)
React的初始化,更新,移除等等操作並不是同步的,使用者編寫的元件(如<ReactComponent/>
)或者平臺特定元件(如<div/>
)這些只是返回需要渲染的資訊,並不是真實DOM,我們通常稱他們為虛擬DOM,React會遍歷這顆虛擬DOM樹來渲染真實的DOM樹。
而且setState()
也並不是同步的,他們的多次呼叫更新會被整合為一次更新,加入更新佇列然後等待更新,再去渲染真實的DOM樹,因為DOM型的操作通常是很耗時的,所以儘量減少DOM相關操作。
DOM之外
React的一個主要特點為編寫的程式碼可以通過工具(如ReactNative,Electron)在多個平臺上執行,因此渲染出來的元素可能不是DOM,因此React將他們分為兩個模組,一個模組為reconciler(調節器),它根據使用者編寫的元件轉換為React可以識別的元素(即虛擬DOM);另一個模組為renderer(渲染器,分為DOM渲染器和Native渲染器),它的作用為根據虛擬DOM渲染為平臺特定的元素。這樣的好處是可以方便React可以在多平臺上執行,而不必太過關注reconciler的程式碼。
相關概念
Fiber
什麼是Fiber?
Fiber是React版本16以後的重要概念。
Fiber的主要目標為:
- 先暫停目前的工作去處理優先順序更高的工作,然後再回來繼續
- 為不同的工作設定不同優先順序
- 重用之前完成的工作
- 終止不再需要的工作
我們都知道呼叫函式時會把它加入執行棧中,等函式執行完後再退出棧,那有沒有辦法可以定製棧的呼叫以更好地優化渲染UI呢?這就是Fiber想要解決的問題,我們可以稱單個Fiber為虛擬的棧幀,它是實現React時序安排的關鍵。
Fiber的結構
type Fiber = {|
// 辨識元件相關的屬性
tag: TypeOfWork,
key: null | string,
type: any,
// 父Fiber或者null
return: Fiber | null,
child: Fiber | null,
sibling: Fiber | null,
index: number,
ref: null | (((handle: mixed) => void) & {_stringRef: ?string}) | RefObject,
memoizedProps: any, // The props used to create the output.
updateQueue: UpdateQueue<any> | null,
memoizedState: any,
mode: TypeOfMode,
effectTag: TypeOfSideEffect,
nextEffect: Fiber | null,
firstEffect: Fiber | null,
lastEffect: Fiber | null,
expirationTime: ExpirationTime,
alternate: Fiber | null,
// 時間
actualDuration?: number,
actualStartTime?: number,
selfBaseTime?: number,
treeBaseTime?: number,
// 除錯
_debugID?: number,
_debugSource?: Source | null,
_debugOwner?: Fiber | null,
_debugIsCurrentlyTiming?: boolean,
|};
複製程式碼
key
、type
這兩個屬性都是用來表示元件的,更新元件的時候先檢查key
是否有改變,如果改變的話則直接摧毀重建;不變的話則繼續檢查type
是否改變,改變則直接摧毀重建;否則重用原來的元件,只是改變元件的屬性。type
可能是使用者定義的函式型或者型別的組合型元件,或者是代表平臺元素的字串(如'div'
)。
pendingProps
、memoizedProps
概念上來說,props
就是一個函式的引數陣列。pendingProps
是Fiber開始執行的時候被設定的,memoizedProps
在執行完之後。每次更新的時候先比較pendingProps
和memoizedProps
,如果它們相同,則表示先前的輸出可以重用,而不必進行多餘的工作。
pendingWorkPriority
一個表面工作優先權的屬性。除NoWork
(它的值為0)以外,數值越大代表有限權越低。
function matchesPriority(fiber, priority) {
return fiber.pendingWorkPriority !== 0 &&
fiber.pendingWorkPriority <= priority
}
複製程式碼