经历一个月的学习整理,站在前人的肩膀上,对React有了一些浅薄的理解,希望记录自己的学习过程的同时也可以给大家带来一点小帮助。如果此系列文章对您有些帮助,还望在座各位义夫义母不吝点赞关注支持,也希望各位大佬拍砖探讨
本系列行文思路如下,本篇属于React中的React的管理员(reconciler与scheduler)
「React Hook原理」
「其他」
「React源码解析之Reconciler运行循环」
reconciler
包的主要作用,将主要功能分为4个方面:
在 ReactFiberWorkLoop.js
中, 承接输入的函数只有 scheduleUpdateOnFiber
在 react-reconciler
对外暴露的 api 函数中, 只要涉及到需要改变 fiber 的操作(无论是首次渲染或后续更新操作), 最后都会间接调用 scheduleUpdateOnFiber
, 所以 scheduleUpdateOnFiber
函数是「输入链路中的必经之路」.
// 唯一接收输入信号的函数
export function scheduleUpdateOnFiber(
fiber: Fiber,
lane: Lane,
eventTime: number,
) {
// ... 省略部分无关代码
//给fiber节点添加优先级
const root = markUpdateLaneFromFiberToRoot(fiber, lane);
if (lane === SyncLane) {
if (
(executionContext & LegacyUnbatchedContext) !== NoContext &&
(executionContext & (RenderContext | CommitContext)) === NoContext
) {
// 直接进行`fiber构造`
// 条件是NoContext,一般是初次构造,不经过调度
performSyncWorkOnRoot(root);
} else {
// 注册调度任务, 经过`Scheduler`包的调度, 间接进行`fiber构造`
ensureRootIsScheduled(root, eventTime);
}
} else {
// 注册调度任务, 经过`Scheduler`包的调度, 间接进行`fiber构造`
// 如果同步优先级,走'Scheduler'调度
ensureRootIsScheduled(root, eventTime);
}
}
与输入环节紧密相连, scheduleUpdateOnFiber
函数之后, 立即进入 ensureRootIsScheduled()
函数
// ... 省略部分无关代码
function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
// 前半部分: 判断是否需要注册新的调度,(如果当前任务已经被挂起则不需要注册新的调度)
const existingCallbackNode = root.callbackNode;
const nextLanes = getNextLanes(
root,
root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,
);
const newCallbackPriority = returnNextLanesPriority();
if (nextLanes === NoLanes) {
return;
}
if (existingCallbackNode !== null) {
const existingCallbackPriority = root.callbackPriority;
if (existingCallbackPriority === newCallbackPriority) {
return;
}
cancelCallback(existingCallbackNode);
}
// 后半部分: 注册调度任务
//其实是在scheduleCallback去创建task,然后加入任务队列里面,后面有详细解释
let newCallbackNode;
if (newCallbackPriority === SyncLanePriority) {
newCallbackNode = scheduleSyncCallback(
performSyncWorkOnRoot.bind(null, root),
);
} else if (newCallbackPriority === SyncBatchedLanePriority) {
newCallbackNode = scheduleCallback(
ImmediateSchedulerPriority,
performSyncWorkOnRoot.bind(null, root),
);
} else {
// concurrent模式下注册任务,然后加入任务队列
const schedulerPriorityLevel = lanePriorityToSchedulerPriority(
newCallbackPriority,
);
newCallbackNode = scheduleCallback(
schedulerPriorityLevel,
performConcurrentWorkOnRoot.bind(null, root),
);
}
root.callbackPriority = newCallbackPriority;
root.callbackNode = newCallbackNode;
}