赞
踩
1 )概述
beginWork
2 )源码
beginWork
就是执行对整棵树的每一个节点进行更新的一个操作import {beginWork} from './ReactFiberBeginWork';
定位到 packages/react-reconciler/src/ReactFiberBeginWork.js
整个文件 export 出去的只有 beginWork 方法
function beginWork( current: Fiber | null, workInProgress: Fiber, renderExpirationTime: ExpirationTime, ): Fiber | null { // 读取了 workInProgress.expirationTime 这个值,这个 expirationTime 是节点上的 expirationTime // 函数第三个参数 renderExpirationTime 是 nextExpirationTimeToWorkOn 和 下面这个 expirationTime 有区别 const updateExpirationTime = workInProgress.expirationTime; // 在 ReactDOM.render 第一次渲染时,第一个节点 current 是有值的, 接下去的节点都是没有的 // 因为我们操作都是在 workInProgress 上操作的 // 所以,workInProgress 创建的 child 节点也是一个 workInProgress 而不是 current // performUnitOfWork 接收的就是 workInProgress if (current !== null) { const oldProps = current.memoizedProps; const newProps = workInProgress.pendingProps; // 下面 renderExpirationTime 标志优先级最大都到哪个点,如果节点上的 expirationTime 比 renderExpirationTime 小 // 说明节点上有优先级更高的任务,在这次渲染里是会执行的,反之,则不需要进行渲染,这个节点可以跳过 // (updateExpirationTime === NoWork || updateExpirationTime > renderExpirationTime) 代表没有更新 或 有更新,但是优先级不高 // hasLegacyContextChanged 属 context 相关api, childContextType 先跳过 // oldProps === newProps 表示 props 一样 if ( oldProps === newProps && !hasLegacyContextChanged() && (updateExpirationTime === NoWork || updateExpirationTime > renderExpirationTime) ) { // This fiber does not have any pending work. Bailout without entering // the begin phase. There's still some bookkeeping we that needs to be done // in this optimized path, mostly pushing stuff onto the stack. // switch 先跳过 switch (workInProgress.tag) { case HostRoot: pushHostRootContext(workInProgress); resetHydrationState(); break; case HostComponent: pushHostContext(workInProgress); break; case ClassComponent: { const Component = workInProgress.type; if (isLegacyContextProvider(Component)) { pushLegacyContextProvider(workInProgress); } break; } case HostPortal: pushHostContainer( workInProgress, workInProgress.stateNode.containerInfo, ); break; case ContextProvider: { const newValue = workInProgress.memoizedProps.value; pushProvider(workInProgress, newValue); break; } case Profiler: if (enableProfilerTimer) { workInProgress.effectTag |= Update; } break; case SuspenseComponent: { const state: SuspenseState | null = workInProgress.memoizedState; const didTimeout = state !== null && state.didTimeout; if (didTimeout) { // If this boundary is currently timed out, we need to decide // whether to retry the primary children, or to skip over it and // go straight to the fallback. Check the priority of the primary // child fragment. const primaryChildFragment: Fiber = (workInProgress.child: any); const primaryChildExpirationTime = primaryChildFragment.childExpirationTime; if ( primaryChildExpirationTime !== NoWork && primaryChildExpirationTime <= renderExpirationTime ) { // The primary children have pending work. Use the normal path // to attempt to render the primary children again. return updateSuspenseComponent( current, workInProgress, renderExpirationTime, ); } else { // The primary children do not have pending work with sufficient // priority. Bailout. const child = bailoutOnAlreadyFinishedWork( current, workInProgress, renderExpirationTime, ); if (child !== null) { // The fallback children have pending work. Skip over the // primary children and work on the fallback. return child.sibling; } else { return null; } } } break; } } // 这个方法跳过该节点与其所有子节点的更新 return bailoutOnAlreadyFinishedWork( current, workInProgress, renderExpirationTime, ); } } // Before entering the begin phase, clear the expiration time. workInProgress.expirationTime = NoWork; // 如果节点有更新,通过节点的 tag,执行不同的方法,进行组件的更新 switch (workInProgress.tag) { case IndeterminateComponent: { const elementType = workInProgress.elementType; return mountIndeterminateComponent( current, workInProgress, elementType, renderExpirationTime, ); } case LazyComponent: { const elementType = workInProgress.elementType; return mountLazyComponent( current, workInProgress, elementType, updateExpirationTime, renderExpirationTime, ); } case FunctionComponent: { const Component = workInProgress.type; const unresolvedProps = workInProgress.pendingProps; const resolvedProps = workInProgress.elementType === Component ? unresolvedProps : resolveDefaultProps(Component, unresolvedProps); return updateFunctionComponent( current, workInProgress, Component, resolvedProps, renderExpirationTime, ); } case ClassComponent: { const Component = workInProgress.type; const unresolvedProps = workInProgress.pendingProps; const resolvedProps = workInProgress.elementType === Component ? unresolvedProps : resolveDefaultProps(Component, unresolvedProps); return updateClassComponent( current, workInProgress, Component, resolvedProps, renderExpirationTime, ); } case HostRoot: return updateHostRoot(current, workInProgress, renderExpirationTime); case HostComponent: return updateHostComponent(current, workInProgress, renderExpirationTime); case HostText: return updateHostText(current, workInProgress); case SuspenseComponent: return updateSuspenseComponent( current, workInProgress, renderExpirationTime, ); case HostPortal: return updatePortalComponent( current, workInProgress, renderExpirationTime, ); case ForwardRef: { const type = workInProgress.type; const unresolvedProps = workInProgress.pendingProps; const resolvedProps = workInProgress.elementType === type ? unresolvedProps : resolveDefaultProps(type, unresolvedProps); return updateForwardRef( current, workInProgress, type, resolvedProps, renderExpirationTime, ); } case Fragment: return updateFragment(current, workInProgress, renderExpirationTime); case Mode: return updateMode(current, workInProgress, renderExpirationTime); case Profiler: return updateProfiler(current, workInProgress, renderExpirationTime); case ContextProvider: return updateContextProvider( current, workInProgress, renderExpirationTime, ); case ContextConsumer: return updateContextConsumer( current, workInProgress, renderExpirationTime, ); case MemoComponent: { const type = workInProgress.type; const unresolvedProps = workInProgress.pendingProps; const resolvedProps = resolveDefaultProps(type.type, unresolvedProps); return updateMemoComponent( current, workInProgress, type, resolvedProps, updateExpirationTime, renderExpirationTime, ); } case SimpleMemoComponent: { return updateSimpleMemoComponent( current, workInProgress, workInProgress.type, workInProgress.pendingProps, updateExpirationTime, renderExpirationTime, ); } case IncompleteClassComponent: { const Component = workInProgress.type; const unresolvedProps = workInProgress.pendingProps; const resolvedProps = workInProgress.elementType === Component ? unresolvedProps : resolveDefaultProps(Component, unresolvedProps); return mountIncompleteClassComponent( current, workInProgress, Component, resolvedProps, renderExpirationTime, ); } default: invariant( false, 'Unknown unit of work tag. This error is likely caused by a bug in ' + 'React. Please file an issue.', ); } }
workInProgress.expirationTime;
这个 expirationTime Fiber 节点上的 expirationTime
root.nextExpirationTimeToWorkOn
// Reset the stack and start working from the root.
resetStack();
nextRoot = root;
nextRenderExpirationTime = expirationTime;
// nextUnitOfWork 是一个Fiber对象, 对应 RootFiber, 而非 FiberRoot
// 更新过程使用的都是 Fiber 对象,不会是 FiberRoot
nextUnitOfWork = createWorkInProgress(
nextRoot.current, // 注意这里
null,
nextRenderExpirationTime,
);
HostRoot
return createFiber(HostRoot, null, null, mode);
HostRoot, null, null, mode
bailoutOnAlreadyFinishedWork
这个方法帮助跳过该节点与其所有子节点的更新function bailoutOnAlreadyFinishedWork( current: Fiber | null, workInProgress: Fiber, renderExpirationTime: ExpirationTime, ): Fiber | null { cancelWorkTimer(workInProgress); if (current !== null) { // Reuse previous context list workInProgress.firstContextDependency = current.firstContextDependency; } if (enableProfilerTimer) { // Don't update "base" render times for bailouts. stopProfilerTimerIfRunning(workInProgress); } // Check if the children have any pending work. const childExpirationTime = workInProgress.childExpirationTime; // 这个值是 React 16.5 加上的,更早跳过更新 // 子树上无更新,或高优先级任务在这次渲染中完成的 则跳过,是一个非常大的优化 if ( childExpirationTime === NoWork || childExpirationTime > renderExpirationTime ) { // The children don't have any work either. We can skip them. // TODO: Once we add back resuming, we should check if the children are // a work-in-progress set. If so, we need to transfer their effects. return null; } else { // This fiber doesn't have work, but its subtree does. Clone the child // fibers and continue. // 如果子树上有更新要执行,拷贝老的child cloneChildFibers(current, workInProgress); return workInProgress.child; } }
let next; if (enableProfilerTimer) { // ... 跳过很多代码 next = beginWork(current, workInProgress, nextRenderExpirationTime); // ... 跳过很多代码 } else { next = beginWork(current, workInProgress, nextRenderExpirationTime); workInProgress.memoizedProps = workInProgress.pendingProps; } // ... 跳过很多代码 if (next === null) { // If this doesn't spawn new work, complete the current work. next = completeUnitOfWork(workInProgress); } ReactCurrentOwner.current = null; // next 不为 null, 直接 return return next;
while (nextUnitOfWork !== null) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。