一、Fiber的含義和作用
(1)每一個ReactElement
對應一個Fiber
對象
(2)記錄節點的各種狀態
比如ClassComponent
中的state
和props
的狀態就是記錄在Fiber
對象上的。
只有當Fiber
對象更新後,纔會更新到ClassComponent
上的this.state
和this.props
上
this
上的state
和props
是根據Fiber
對象的state
、props
更新的。
這實際上也方便了ReactHooks
,因爲hooks
是爲FunctionalComponent
服務的。雖然FunctionalComponent
沒有this
,但Fiber
上有,是可以拿到state
和props
的
(3)串聯整個應用形成樹結構
每個ReactElement
通過props.children
與其他ReactElement
連結起來
說明:
① ReactElement
只會把子節點(props.children
)的第一個子節點當做child
節點,其餘的子節點(也就是第一個子節點的兄弟節點)都是從第一個子節點開始,依次單向連接至後一個兄弟節點
② 每個子節點都會指向父節點(紅箭頭),也就是Fiber
對象的return
屬性
export type Fiber = {|
//指向該對象在Fiber節點樹中的`parent`,用來在處理完該節點後返回
//即流程圖上的紅線
return: Fiber | null,
}
串聯過程:
① 任一 葉子 節點A
,如果有兄弟節點,則去單向向後遍歷兄弟節點,最後return
到父節點
② 父節點的child
節點不是剛剛的子節點A
的話,則從child
節點遍歷到A
前的節點,並再次return
到父節點
③ 該父節點執行 ①、②
根據圖1舉例:
比如從左下角的input
節點開始,它沒有兄弟節點,則return
到父組件Input
(因爲父節點有且只有一個,所以必定return
到父節點)
Input
有兄弟節點List
,List
又有child
節點,則從child
節點往後單向遍歷兄弟節點,最後return
到List
List
又return
到div
,div
的child
節點已被遍歷,則return
到App
節點,App
,App
又return
到所有Fiber
對象的根對象RootFiber
對象
這樣,就將整個應用遍歷完了。
二、Fiber對象
源碼:
// A Fiber is work on a Component that needs to be done or was done. There can
// be more than one per component.
//Fiber對應一個即將update或已經update的組件,
// 一個組件可以有一個或多個Fiber
export type Fiber = {|
// These first fields are conceptually members of an Instance. This used to
// be split into a separate type and intersected with the other Fiber fields,
// but until Flow fixes its intersection bugs, we've merged them into a
// single type.
// An Instance is shared between all versions of a component. We can easily
// break this out into a separate object to avoid copying so much to the
// alternate versions of the tree. We put this on a single object for now to
// minimize the number of objects created during the initial render.
// Tag identifying the type of fiber.
//標記不同的組件類型
//有原生的DOM節點,有React自己的節點
tag: WorkTag,
// Unique identifier of this child.
//ReactElement裏面的key
key: null | string,
// The value of element.type which is used to preserve the identity during
// reconciliation of this child.
//ReactElement.type,也就是我們調用createElement的第一個參數
elementType: any,
// The resolved function/class/ associated with this fiber.
//異步組件resolve之後返回的內容,一般是function或class
//比如懶加載
type: any,
// The local state associated with this fiber.
//當前Fiber的狀態(比如瀏覽器環境就是DOM節點)
//不同類型的實例都會記錄在stateNode上
//比如DOM組件對應DOM節點實例
//ClassComponent對應Class實例
//FunctionComponent沒有實例,所以stateNode值爲null
//state更新了或props更新了均會更新到stateNode上
stateNode: any,
// Conceptual aliases
// parent : Instance -> return The parent happens to be the same as the
// return fiber since we've merged the fiber and instance.
// Remaining fields belong to Fiber
// The Fiber to return to after finishing processing this one.
// This is effectively the parent, but there can be multiple parents (two)
// so this is only the parent of the thing we're currently processing.
// It is conceptually the same as the return address of a stack frame.
//指向該對象在Fiber節點樹中的`parent`,用來在處理完該節點後返回
//即流程圖上的紅線
return: Fiber | null,
// Singly Linked List Tree Structure.
//單鏈表樹結構
//指向自己的第一個子節點
child: Fiber | null,
//指向自己的兄弟結構
//兄弟節點的return指向同一個父節點
sibling: Fiber | null,
index: number,
// The ref last used to attach this node.
// I'll avoid adding an owner field for prod and model that as functions.
//ref屬性
ref: null | (((handle: mixed) => void) & {_stringRef: ?string}) | RefObject,
// Input is the data coming into process this fiber. Arguments. Props.
//新的變動帶來的新的props,即nextProps
pendingProps: any, // This type will be more specific once we overload the tag.
//上一次渲染完成後的props,即 props
memoizedProps: any, // The props used to create the output.
// A queue of state updates and callbacks.
//該Fiber對應的組件,所產生的update,都會放在該隊列中
updateQueue: UpdateQueue<any> | null,
// The state used to create the output
//上次渲染的state,即 state
//新的state由updateQueue計算得出,並覆蓋memoizedState
memoizedState: any,
// Dependencies (contexts, events) for this fiber, if it has any
//一個列表,存在該Fiber依賴的contexts,events
dependencies: Dependencies | null,
// Bitfield that describes properties about the fiber and its subtree. E.g.
// the ConcurrentMode flag indicates whether the subtree should be async-by-
// default. When a fiber is created, it inherits the mode of its
// parent. Additional flags can be set at creation time, but after that the
// value should remain unchanged throughout the fiber's lifetime, particularly
// before its child fibers are created.
//mode有conCurrentMode和strictMode
//用來描述當前Fiber和其他子樹的Bitfield
//共存的模式表示這個子樹是否默認是 異步渲染的
//Fiber剛被創建時,會繼承父Fiber
//其他標識也可以在創建的時候被設置,但是創建之後不該被修改,特別是它的子Fiber創建之前
mode: TypeOfMode,
//以下屬性是副作用
//副作用是 標記組件哪些需要更新的工具、標記組件需要執行哪些生命週期的工具
// Effect
effectTag: SideEffectTag,
// Singly linked list fast path to the next fiber with side-effects.
nextEffect: Fiber | null,
// The first and last fiber with side-effect within this subtree. This allows
// us to reuse a slice of the linked list when we reuse the work done within
// this fiber.
firstEffect: Fiber | null,
lastEffect: Fiber | null,
// Represents a time in the future by which this work should be completed.
// Does not include work found in its subtree.
//代表任務在未來的哪個時間點 應該被完成
//不包括該Fiber的子樹產生的任務
expirationTime: ExpirationTime,
// This is used to quickly determine if a subtree has no pending changes.
//快速確定子樹中是否有 update
//如果子節點有update的話,就記錄應該更新的時間
childExpirationTime: ExpirationTime,
// This is a pooled version of a Fiber. Every fiber that gets updated will
// eventually have a pair. There are cases when we can clean up pairs to save
// memory if we need to.
// 在FIber樹更新的過程中,每個Fiber都有與其對應的Fiber
//我們稱之爲 current <==> workInProgress
//在渲染完成後,會交換位置
//doubleBuffer Fiber在更新後,不用再重新創建對象,
// 而是複製自身,並且兩者相互複用,用來提高性能
alternate: Fiber | null,
// Time spent rendering this Fiber and its descendants for the current update.
// This tells us how well the tree makes use of sCU for memoization.
// It is reset to 0 each time we render and only updated when we don't bailout.
// This field is only set when the enableProfilerTimer flag is enabled.
actualDuration?: number,
// If the Fiber is currently active in the "render" phase,
// This marks the time at which the work began.
// This field is only set when the enableProfilerTimer flag is enabled.
actualStartTime?: number,
// Duration of the most recent render time for this Fiber.
// This value is not updated when we bailout for memoization purposes.
// This field is only set when the enableProfilerTimer flag is enabled.
selfBaseDuration?: number,
// Sum of base times for all descedents of this Fiber.
// This value bubbles up during the "complete" phase.
// This field is only set when the enableProfilerTimer flag is enabled.
treeBaseDuration?: number,
// Conceptual aliases
// workInProgress : Fiber -> alternate The alternate used for reuse happens
// to be the same as work in progress.
// __DEV__ only
_debugID?: number,
_debugSource?: Source | null,
_debugOwner?: Fiber | null,
_debugIsCurrentlyTiming?: boolean,
_debugNeedsRemount?: boolean,
// Used to verify that the order of hooks does not change between renders.
_debugHookTypes?: Array<HookType> | null,
|};
解析:
熟悉Fiber
的含義和屬性含義就可以了,之後講React
更新的時候,還會提到它。
三、總結
(1)Fiber
的三個作用
(2)單向遍歷
(3)props.children
連接
(4)子指父
(5)doubleBuffer
(完)