记录学习过程,如有错误欢迎指出
前两篇文章我们把
performConcurrentWorkOnRoot讲了,本篇文章会将和performConcurrentWorkOnRoot对应的另外一个函数performSyncWorkOnRoot
开始之前(必看)
React version 18.2.0
DEV代码可以忽略,下面正文我使用省略号就代表是dev相关的代码,包含hydrate字样的也请忽略,那是服务端渲染相关,望周知
我使用深度优先(🐶)的方式讲解:即遇到函数先进入函数,执行完函数后,又退回之前的函数.而不是在一个函数中讲完了再讲函数中执行的函数(希望能听懂我在说什么^v^)
因为使用了深度优先的方式讲解,
耦合比较重,不建议跳着看
performSyncWorkOnRoot(未完)
function performSyncWorkOnRoot(root) {
....
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
throw new Error('Should not already be working.');
}
//消除被动效果,在performConcurrentWorkOnRoot中有讲到过,这里不再赘述
flushPassiveEffects();
//获取下一个车道
let lanes = getNextLanes(root, NoLanes);
if (!includesSomeLane(lanes, SyncLane)) {
//安排进行调度
ensureRootIsScheduled(root, now());
return null;
}
//renderRootSync函数也在上一章中讲解了
let exitStatus = renderRootSync(root, lanes);
if (root.tag !== LegacyRoot && exitStatus === RootErrored) {
// 如果第一次renderRootSync出错了,那么react将再尝试一次,最后如果还是失败了
// 那么将会抛弃这个节点
const errorRetryLanes = getLanesToRetrySynchronouslyOnError(root);
// 判断第二次是否失败
if (errorRetryLanes !== NoLanes) {
lanes = errorRetryLanes;
// 如果失败,调用recoverFromConcurrentError
// 我们进入recoverFromConcurrentError看一下
exitStatus = recoverFromConcurrentError(root, errorRetryLanes);
}
}
.....
recoverFromConcurrentError
function recoverFromConcurrentError(root, errorRetryLanes) {
// 保存上一次错误的原因
const errorsFromFirstAttempt = workInProgressRootConcurrentErrors;
if (isRootDehydrated(root)) {
// prepareFreshStack:准备双缓存
const rootWorkInProgress = prepareFreshStack(root, errorRetryLanes);
rootWorkInProgress.flags |= ForceClientRender;
....
}
// 同步调和
const exitStatus = renderRootSync(root, errorRetryLanes);
// 判断调和状态
if (exitStatus !== RootErrored) {
// Successfully finished rendering on retry
//第一次出现的错误被恢复了,现在将这次操作记录下来
const errorsFromSecondAttempt = workInProgressRootRecoverableErrors;
workInProgressRootRecoverableErrors = errorsFromFirstAttempt;
// 保证两次调用的`因果关系`
if (errorsFromSecondAttempt !== null) {
queueRecoverableErrors(errorsFromSecondAttempt);
}
} else {
// The UI failed to recover.
}
return exitStatus;
}
performSyncWorkOnRoot(完)
....
// 出现致命错误的情况
if (exitStatus === RootFatalErrored) {
const fatalError = workInProgressRootFatalError;
prepareFreshStack(root, NoLanes);
markRootSuspended(root, lanes);
ensureRootIsScheduled(root, now());
throw fatalError;
}
// 没有调和完成
if (exitStatus === RootDidNotComplete) {
throw new Error('Root did not complete. This is a bug in React.');
}
// 现在就得到了两颗一直的树
// 因为是同步渲染,不管有什么事情暂停,这里都会提交
const finishedWork: Fiber = (root.current.alternate: any);
root.finishedWork = finishedWork;
root.finishedLanes = lanes;
// Sync模式下的进入的commit
commitRoot(
root, /**fiberRootNode */
workInProgressRootRecoverableErrors, /**null */
workInProgressTransitions, /**null */
);
// 退出之前的回调
ensureRootIsScheduled(root, now());
return null;
}
总结
至此,render阶段就结束了,总结一下,render阶段就是对sync和concurrent模式的判断,从而执行不同的逻辑,多看几遍还是可以理解的,后面就是commit的阶段了,commit阶段也是react最后阶段,执行完毕后浏览器中就会呈现页面
我也画完了React三个阶段流程图,后面我会上传到github,欢迎大家star
记录学习过程,如有错误欢迎指出