React源码解析之RootFiber

43次阅读

共计 6335 个字符,预计需要花费 16 分钟才能阅读完成。

一、Fiber 的含义和作用
(1)每一个ReactElement 对应一个 Fiber 对象

(2)记录节点的各种状态
比如 ClassComponent 中的 stateprops的状态就是记录在 Fiber 对象上的。

只有当 Fiber 对象更新后,才会更新到 ClassComponent 上的 this.statethis.props

this上的 stateprops是根据 Fiber 对象的 stateprops 更新的。

这实际上也方便了 ReactHooks,因为hooks 是为 FunctionalComponent 服务的。虽然 FunctionalComponent 没有 this,但Fiber 上有,是可以拿到 stateprops

(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有兄弟节点 ListList 又有 child 节点,则从 child 节点往后单向遍历兄弟节点,最后 returnList

Listreturndivdivchild 节点已被遍历,则 returnApp节点,AppAppreturn 到所有 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 更新的时候,还会提到它。

GitHub:
https://github.com/AttackXiaoJinJin/reactExplain/blob/master/react16.8.6/packages/react-reconciler/src/ReactFiber.js

三、总结
(1)Fiber 的三个作用
(2)单向遍历
(3)props.children 连接
(4)子指父
(5)doubleBuffer


(完)

正文完
 0