Fiber
需要注意的地方:
- 组件第一次运行时为
fibetmount阶段;后续更新为fiberupdate阶段。 - 函数组件
mount时fibet.tag为IndeterminateComponent。- 历史遗留问题,旧版本支持 函数工厂 组件,函数返回一个有
render函数的对象,会被当做ClassComponent处理。 此时tag赋重新赋值为ClassCompoent否则赋值为FunctionComponent
- 历史遗留问题,旧版本支持 函数工厂 组件,函数返回一个有
key会强制转换string类型。key = '' + config.key;
export type Fiber = {|
// 类型 eg: 0:FunctionComponent,1:ClassComponent,2:IndeterminateComponent
tag: WorkTag,
// fiber key
key: null | string,
// diff中保存type
elementType: any,
// fiber的类型 host/function/class/ eg: 'div'; function FC(); class C extend Component;
type: any,
// 宿主实例。 浏览器中为DOM
stateNode: any,
// fiber父节点
return: Fiber | null,
// 第一个孩子节点
child: Fiber | null,
// 兄弟节点
sibling: Fiber | null,
// fiber是依据jsx生成的。
// 此fiber对应的jsx,在jsxChildren中的位置索引
// eg:<App><input/><textarea/></App> textareaFiber的index为1
index: number,
// ref引用
ref:
| null
| (((handle: mixed) => void) & {_stringRef: ?string, ...})
| RefObject,
pendingProps: any, // 渲染中正在计算的props
memoizedProps: any, // 实际使用的props。也可以认为是上一次渲染的props缓存值。
// 更新队列 类组件处理state;函数组件是hooks effect;原生(DOM)组件是属性变化;
updateQueue: mixed,
// 实际使用的state。也可以认为是上一次渲染的state缓存值。
memoizedState: any,
// 所依赖的context,event
dependencies: Dependencies | null,
// 模式 eg: ConcurrentMode ; StrictLegacyMode
mode: TypeOfMode,
// Effect fiber的副作用
// 二进制补码。 来标记fiber的effect eg:Update Placment Deletion Ref 相关Hooks
flags: Flags,
// 子树的effect集合,用于性能优化。eg:为NoFlags直接跳过子树
subtreeFlags: Flags,
// 需要删除的child
deletions: Array<Fiber> | null,
// 已被废弃;
// commit阶段通过effectList来进行性能优化
nextEffect: Fiber | null,
firstEffect: Fiber | null,
lastEffect: Fiber | null,
// 优先级
lanes: Lanes,
// 子树优先级
childLanes: Lanes,
// 备用; newFiber与oldFiber进行切换;
alternate: Fiber | null,
// Profiler使用;记录更新时长
actualDuration?: number,
actualStartTime?: number,
selfBaseDuration?: number,
treeBaseDuration?: number,
// dev debug
_debugSource?: Source | null,
_debugOwner?: Fiber | null,
_debugIsCurrentlyTiming?: boolean,
_debugNeedsRemount?: boolean,
_debugHookTypes?: Array<HookType> | null,
|};
fiber中alternate切换 -- createWorkInProgress
先看函数
function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
let workInProgress = current.alternate;
// workInProgress === null 为 mount阶段
if (workInProgress === null) {
workInProgress = createFiber(
current.tag,
pendingProps,
current.key,
current.mode,
);
workInProgress.elementType = current.elementType;
workInProgress.type = current.type;
workInProgress.stateNode = current.stateNode;
// currentFiber与newFiber连接
workInProgress.alternate = current;
current.alternate = workInProgress;
} else {
// update阶段
// 复用一些属性
workInProgress.pendingProps = pendingProps;
workInProgress.type = current.type;
workInProgress.flags = NoFlags;
workInProgress.subtreeFlags = NoFlags;
workInProgress.deletions = null;
}
// flags置空 (除StaticMask)
workInProgress.flags = current.flags & StaticMask;
// 复用一些属性
workInProgress.childLanes = current.childLanes;
workInProgress.lanes = current.lanes;
workInProgress.child = current.child;
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
// 克隆 dependencies
const currentDependencies = current.dependencies;
workInProgress.dependencies =
currentDependencies === null
? null
: {
lanes: currentDependencies.lanes,
firstContext: currentDependencies.firstContext,
};
// 复用一些属性
workInProgress.sibling = current.sibling;
workInProgress.index = current.index;
workInProgress.ref = current.ref;
return workInProgress;
}
- 时机:
- 在diif时
reconcileChildFibers()为jsxChildren创建fiber - 其中复用
fiber, 调用createWorkInProgress(),切换workInProgress - 无法复用新创建的
fiber,调用createFiberFromTypeAndProps()创建fiber
- 在diif时
- workInProgress:
workInProgress是新旧交替,alternate是新旧的连接点- 新旧fiber对象被复用,而不是新创建,应该是省内存空间
workInProgress是本次更新对应的fiber,alternate则是上次更新对应的fiber(目前页面呈现的fiber)
- alternate切换示意图
update a b
0: current(第一次为null) <--alternate--> workInProgress
切换: workInProgress = current.alternate
workInProgress = createFiber() ↓ (上次的workInProgress是本次的current)
(第一次时current为null,需要创建fiber)
1: workInProgress <--alternate--> current
切换: ↓ workInProgress = current.alternate
2: current <--alternate--> workInProgress
切换: workInProgress = current.alternate ↓
3: workInProgress <--alternate--> current
- 在最终渲染时,直接切换为
alternate即可
const finishedWork: Fiber = root.current.alternate;
root.finishedWork = finishedWork;
root.finishedLanes = lanes;
commitRoot(root);
root.current = finishedWork; // commitRoot函数中执行
Fiber的头节点
// 伪代码 模拟表示头结点
root:FiberRootNode = {
current:Fiber = {
stateNode = root // 这里是循环引用
memoizedState = {element:null} // 这是项目JSX入口
updateQueue // 初始化updateQueue
}
}
root.current表示正在程序的fiber树