React源码系列
- React源码解析之 Fiber结构的创建
- React源码解析 之 Fiber的渲染(1)
- React源码解析 之Fiber的渲染(2)beginWork
- React源码解析 之 Fiber的渲染(3)终
completeWork
相比较beginWork阶段来说,completeWork阶段,处理就比较简单了。同样的,对于completeWork,也是通过workInProgress.tag来判断,走哪些类型逻辑。
function completeWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
): Fiber | null {
const newProps = workInProgress.pendingProps;
switch (workInProgress.tag) {
case IndeterminateComponent:
case LazyComponent:
case SimpleMemoComponent:
case FunctionComponent:
case ForwardRef:
case Fragment:
case Mode:
case Profiler:
case ContextConsumer:
case MemoComponent:
bubbleProperties(workInProgress);
return null;
case ClassComponent: {
const Component = workInProgress.type;
if (isLegacyContextProvider(Component)) {
popLegacyContext(workInProgress);
}
bubbleProperties(workInProgress);
return null;
}
对于completeWork阶段来说,很多类型是不需要处理的,对context栈进行置空处理,和处理一些lane。
因此,这里主要说下HostText和HostComponent类型。
HostText
case HostText: {
const newText = newProps;
// 判断是否是update状态。
if (current && workInProgress.stateNode != null) {
const oldText = current.memoizedProps;
//传入Text类型到workInProgress.stateNode上
updateHostText(current, workInProgress, oldText, newText);
} else {
if (typeof newText !== 'string') {
//...
}
const rootContainerInstance = getRootHostContainer();
const currentHostContext = getHostContext();
//...
if (wasHydrated) {
//...
} else {
// 通过createTextNode的TextNode
workInProgress.stateNode = createTextInstance(
newText,
rootContainerInstance,
currentHostContext,
workInProgress,
);
}
}
return null;
}
对于HostText类型,通过current && workInProgress.stateNode != null条件,来区分当前节点,处于什么阶段。
如果处于update阶段的话,即条件为true:此时通过markUpdate(workInProgress),打上标记,当处于commit阶段再执行。
如果处于mounted阶段的话,即条件为false:通过createTextNode的创建TextNode,返回给workInProgress.stateNode。
HostComponent
HostComponent为原生DOM组件,通过current !== null && workInProgress.stateNode != null区分mounted:false和update:true阶段。
update:
调用updateHostComponent函数,如果current.ref !== workInProgress.ref为true,标记markRef(workInProgress)。
对于updateHostComponent函数,复用workInProgress.stateNode为instance。
instance: Instance = workInProgress.stateNode;
调用prepareUpdate函数,返回updateQueue。
export function prepareUpdate(
domElement: Instance,
type: string,
oldProps: Props,
newProps: Props,
rootContainerInstance: Container,
hostContext: HostContext,
): null | Array<mixed> {
// 对属性进行取差
return diffProperties(
domElement,
type,
oldProps,
newProps,
rootContainerInstance,
);
}
commitRoot阶段
在这里简单说下commitRoot阶段。
对于一个commitRoot阶段,包含三个阶段:before mutation、mutation、layout阶段。
before mutation:
初始化清空下,清空副作用,调用commitRootImpl。然后再重置下状态
// ...
// 清除回调
root.callbackNode = null;
root.callbackPriority = NoLanePriority;
//合并lane
let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);
// 重置优先级
markRootFinished(root, remainingLanes);
//重置全局变量
if (root === workInProgressRoot) {
//处于
workInProgressRoot = null;
workInProgress = null;
workInProgressRootRenderLanes = NoLanes;
}
//...
// 调度useEffect
if ((effectTag & Passive) !== NoEffect) {
if (!rootDoesHavePassiveEffects) {
rootDoesHavePassiveEffects = true;
scheduleCallback(NormalSchedulerPriority, () => {
flushPassiveEffects();
return null;
});
}
}
nextEffect = nextEffect.nextEffect;
调用commitBeforeMutationEffects函数,判断是否是classComponent执行生命周期getSnapshotBeforeUpdate
该函数的返回给componentDidUpdate
commitBeforeMutationEffects
//
export function commitBeforeMutationEffects(
root: FiberRoot,
firstChild: Fiber,
) {
//...
nextEffect = firstChild;
commitBeforeMutationEffects_begin();
//...
return shouldFire;
}
//
function commitBeforeMutationEffects_begin() {
while (nextEffect !== null) {
const fiber = nextEffect;
//...
const child = fiber.child;
if (
(fiber.subtreeFlags & BeforeMutationMask) !== NoFlags &&
child !== null
) {
//...
nextEffect = child;
} else {
// Before Mutation 处理完成
commitBeforeMutationEffects_complete();
}
}
}
function commitBeforeMutationEffects_complete() {
while (nextEffect !== null) {
const fiber = nextEffect;
if (__DEV__) {
//...
} else {
try {
//处理副作用
commitBeforeMutationEffectsOnFiber(fiber);
} catch (error) {
//...
}
}
// 处理兄弟节点
const sibling = fiber.sibling;
if (sibling !== null) {
nextEffect = sibling;
return;
}
nextEffect = fiber.return;
}
}
function commitBeforeMutationEffectsOnFiber(finishedWork: Fiber) {
const current = finishedWork.alternate;
const flags = finishedWork.flags;
// ...
if ((flags & Snapshot) !== NoFlags) {
setCurrentDebugFiberInDEV(finishedWork);
switch (finishedWork.tag) {
case FunctionComponent:
case ForwardRef:
case SimpleMemoComponent: {
break;
}
case ClassComponent: {
if (current !== null) {
const prevProps = current.memoizedProps;
const prevState = current.memoizedState;
const instance = finishedWork.stateNode;
// 调用生命周期
const snapshot = instance.getSnapshotBeforeUpdate(
finishedWork.elementType === finishedWork.type
? prevProps
: resolveDefaultProps(finishedWork.type, prevProps),
prevState,
);
//将处理的返回值缓存起来
instance.__reactInternalSnapshotBeforeUpdate = snapshot;
}
break;
}
mutation
进入mutation阶段,调用commitMutationEffects(root, finishedWork);函数
commitMutationEffects
export function commitMutationEffects(root: FiberRoot, firstChild: Fiber) {
nextEffect = firstChild;
commitMutationEffects_begin(root);
}
//...调用commitMutationEffectsOnFiber处理函数类型
commitMutationEffectsOnFiber(fiber, root);
//...
function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) {
const flags = finishedWork.flags;
// 根据primaryFlag判断当前组件处于什么组件状态
const primaryFlags = flags & (Placement | Update | Hydrating);
outer: switch (primaryFlags) {
//...处理commitWork
case Update: {
const current = finishedWork.alternate;
commitWork(current, finishedWork);
break;
}
}
}
Layout阶段
到达此阶段后,说明DOM已经渲染完成,(说明mutation阶段完成)。
在该阶段,调用的生命周期和hook已经可以访问到DOM元素了。
commitLayoutEffects(finishedWork, root, lanes);
|
commitLayoutEffects_begin(finishedWork, root, committedLanes);
|
commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);
|
commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
function commitLayoutEffectOnFiber(
finishedRoot: FiberRoot,
current: Fiber | null,
finishedWork: Fiber,
committedLanes: Lanes,
): void {
if ((finishedWork.flags & (Update | Callback)) !== NoFlags) {
switch (finishedWork.tag) {
// 以下都是FunctionComponent及相关类型
case FunctionComponent:
case ForwardRef:
case SimpleMemoComponent:
case Block: {
// 执行useLayoutEffect的回调函数
commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
// 调度useEffect的销毁函数与回调函数
schedulePassiveEffects(finishedWork);
return;
}
case ClassComponent: {
const instance = finishedWork.stateNode;
if (finishedWork.flags & Update) {
//...
//组件加载完成调用生命周期
instance.componentDidMount();
} else {
const prevProps =
finishedWork.elementType === finishedWork.type
? current.memoizedProps
: resolveDefaultProps(finishedWork.type, current.memoizedProps);
const prevState = current.memoizedState;
//...
//调用componentDidUpdate生命周期传入getSnapshotBeforeUpdate的返回值
instance.componentDidUpdate(
prevProps,
prevState,
instance.__reactInternalSnapshotBeforeUpdate,
);
}
}
// 更新队列
commitUpdateQueue(finishedWork, updateQueue, instance);
}
break;
}
//...
对于FunctionComponent组件,调用commitHookEffectListMount函数执行副作用。
// 执行副作用useEffect
function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);
const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
if (lastEffect !== null) {
const firstEffect = lastEffect.next;
let effect = firstEffect;
do {
if ((effect.tag & tag) === tag) {
// Mount
const create = effect.create;
effect.destroy = create();
effect = effect.next;
} while (effect !== firstEffect);
}
}
对于classComponent组件,根据finishedWork.flags & Update进行判断,mount阶段,调用componentDidMount函数,在update阶段调用instance.componentDidUpdate函数。
最后调用commitUpdateQueue函数,处理effect函数,调用后调。
export function commitUpdateQueue<State>(
finishedWork: Fiber,
finishedQueue: UpdateQueue<State>,
instance: any,
): void {
// Commit the effects
const effects = finishedQueue.effects;
finishedQueue.effects = null;
if (effects !== null) {
effects.forEach(effect => {
const callback = effect.callback;
if (callback !== null) {
effect.callback = null;
callCallback(callback, instance);
}
})
commitUpdateQueue主要解决setState的回调。
结束
这几篇文章主要介绍了React.render的基本流程。