一、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
更新的时候,还会提到它。
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
(完)