React源码解析之RootFiber
一、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
(完)