React源碼解析之RootFiber

1、Fiber的含義和做用
(1)每個ReactElement對應一個Fiber對象javascript

(2)記錄節點的各類狀態
好比ClassComponent中的stateprops的狀態就是記錄在Fiber對象上的。php

只有當Fiber對象更新後,纔會更新到ClassComponent上的this.statethis.propsjava

this上的stateprops是根據Fiber對象的stateprops更新的。node

這實際上也方便了ReactHooks,由於hooks是爲FunctionalComponent服務的。雖然FunctionalComponent沒有this,但Fiber上有,是能夠拿到statepropsreact

(3)串聯整個應用造成樹結構
每一個ReactElement經過props.children與其餘ReactElement連結起來git

圖1
圖1

說明:
ReactElement只會把子節點(props.children)的第一個子節點當作child節點,其他的子節點(也就是第一個子節點的兄弟節點)都是從第一個子節點開始,依次單向鏈接至後一個兄弟節點github

② 每一個子節點都會指向父節點(紅箭頭),也就是Fiber對象的return屬性web

export type Fiber = {|
  //指向該對象在Fiber節點樹中的`parent`,用來在處理完該節點後返回
  //即流程圖上的紅線
  return: Fiber | null,
}
複製代碼

串聯過程:
① 任一 葉子 節點A,若是有兄弟節點,則去單向向後遍歷兄弟節點,最後return到父節點
② 父節點的child節點不是剛剛的子節點A的話,則從child節點遍歷到A前的節點,並再次return到父節點
③ 該父節點執行 ①、②瀏覽器

根據圖1舉例:
好比從左下角的input節點開始,它沒有兄弟節點,則return到父組件Input(由於父節點有且只有一個,因此一定return到父節點)app

Input有兄弟節點ListList又有child節點,則從child節點日後單向遍歷兄弟節點,最後returnList

Listreturndivdivchild節點已被遍歷,則returnApp節點,AppAppreturn到全部Fiber對象的根對象RootFiber對象

這樣,就將整個應用遍歷完了。

2、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更新的時候,還會提到它。

GitHub:
github.com/AttackXiaoJ…

3、總結
(1)Fiber的三個做用
(2)單向遍歷
(3)props.children鏈接
(4)子指父
(5)doubleBuffer


(完)

相關文章
相關標籤/搜索