今天来讲一下render函数到render阶段的流程,render阶段和render函数不是同一个东西哦!
render阶段是react Fiber节点创建的阶段,也是我们diff算法执行的主要阶段。
render函数是挂载和渲染jsx节点的入口函数。
scheduleUpdateOnFiber
scheduleUpdateOnFiber函数从执行栈来看是在updateContainer函数中调用,主要是处理优先级和挂载更新节点
function scheduleUpdateOnFiber(
fiber: Fiber,
lane: Lane,
eventTime: number,
) {
// 判断是否是无限嵌套的update队列,例如render函数里面放setState,最大的值是50
checkForNestedUpdates();
// 测试环境使用
warnAboutRenderPhaseUpdatesInDEV(fiber);
// 更新优先级,先忽略
const root = markUpdateLaneFromFiberToRoot(fiber, lane);
// ...
if (lane === SyncLane) {
if (
// Check if we're inside unbatchedUpdates
(executionContext & LegacyUnbatchedContext) !== NoContext &&
// Check if we're not already rendering
(executionContext & (RenderContext | CommitContext)) === NoContext
) {
// Register pending interactions on the root to avoid losing traced interaction data.
// 跟踪这些update,并计数、检测它们是否会报错
schedulePendingInteractions(root, lane);
// This is a legacy edge case. The initial mount of a ReactDOM.render-ed
// root inside of batchedUpdates should be synchronous, but layout updates
// should be deferred until the end of the batch.
// 执行Fiber相关事情
performSyncWorkOnRoot(root);
} else {
// 更新
} else {
...
}
...
mostRecentlyUpdatedRoot = root;
}
performSyncWorkOnRoot
render阶段和commit阶段执行函数
function performSyncWorkOnRoot(root) {
invariant(
(executionContext & (RenderContext | CommitContext)) === NoContext,
'Should not already be working.',
);
// 处理 useEffect
flushPassiveEffects();
let lanes;
let exitStatus;
if (
root === workInProgressRoot &&
includesSomeLane(root.expiredLanes, workInProgressRootRenderLanes)
) {
// 渲染过期节点
lanes = workInProgressRootRenderLanes;
exitStatus = renderRootSync(root, lanes);
if (
includesSomeLane(
workInProgressRootIncludedLanes,
workInProgressRootUpdatedLanes,
)
) {
// The render included lanes that were updated during the render phase.
// For example, when unhiding a hidden tree, we include all the lanes
// that were previously skipped when the tree was hidden. That set of
// lanes is a superset of the lanes we started rendering with.
//
// Note that this only happens when part of the tree is rendered
// concurrently. If the whole tree is rendered synchronously, then there
// are no interleaved events.
lanes = getNextLanes(root, lanes);
exitStatus = renderRootSync(root, lanes);
}
} else {
// 计算优先级
lanes = getNextLanes(root, NoLanes);
// render入口函数
exitStatus = renderRootSync(root, lanes);
}
// ...
}
renderRootSync
render阶段执行函数,部分注释
function renderRootSync(root: FiberRoot, lanes: Lanes) {
// 旧的上下文
const prevExecutionContext = executionContext;
// 切换到渲染执行上下文
executionContext |= RenderContext;
// 初始上下文为8 ,非批量同步: 8 , RenderContext: render: 16
// hooks相关,返回hook相关函数
const prevDispatcher = pushDispatcher(root);
// If the root or lanes have changed, throw out the existing stack
// and prepare a fresh one. Otherwise we'll continue where we left off.
if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
// 构建 workInProgressFiber 树及 rootFiber
prepareFreshStack(root, lanes);
// 初始渲染不执行 内部条件判断不成立
startWorkOnPendingInteractions(root, lanes);
}
const prevInteractions = pushInteractions(root);
do {
try {
// 循环处理workInProgress
workLoopSync();
break;
} catch (thrownValue) {
handleError(root, thrownValue);
}
} while (true);
resetContextDependencies();
if (enableSchedulerTracing) {
popInteractions(((prevInteractions: any): Set<Interaction>));
}
executionContext = prevExecutionContext;
popDispatcher(prevDispatcher);
if (workInProgress !== null) {
// This is a sync render, so we should have finished the whole tree.
invariant(
false,
'Cannot commit an incomplete root. This error is likely caused by a ' +
'bug in React. Please file an issue.',
);
}
// Set this to null to indicate there's no in-progress render.
workInProgressRoot = null;
workInProgressRootRenderLanes = NoLanes;
return workInProgressRootExitStatus;
}
workLoopSync
function workLoopSync() {
// Already timed out, so perform work without checking if we need to yield.
while (workInProgress !== null) {
performUnitOfWork(workInProgress);
}
}
performUnitOfWork
function performUnitOfWork(unitOfWork: Fiber): void {
// 获取current树
const current = unitOfWork.alternate;
// 开发环境忽略
setCurrentDebugFiberInDEV(unitOfWork);
let next;
if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {
startProfilerTimer(unitOfWork);
// beginWork入口函数
next = beginWork(current, unitOfWork, subtreeRenderLanes);
stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
} else {
next = beginWork(current, unitOfWork, subtreeRenderLanes);
}
resetCurrentDebugFiberInDEV();
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
// completeWork入口
completeUnitOfWork(unitOfWork);
} else {
workInProgress = next;
}
ReactCurrentOwner.current = null;
}
总结
本次主要是继render后的流程展示
- scheduler阶段的updateContatiner函数调用scheduleUpdateOnFiber函数
- 当调用 performSyncWorkOnRoot 方法就表示正式进入 render 阶段,在renderRootSync进行构建。
- 判断是否有 workInProgress Fiber 树,mount首次挂载没有就prepareFreshStack构建。
- workLoopSync主要循环处理workInProgress,在Concurrent模式下还有shouldYield判断条件可中断处理(这是后话)
- workLoopSync循环执行performUnitOfWork,performUnitOfWork是beginWork和completeWork入口。
- 下一章节主要讲beginWork执行流程敬请期待!