React18.2.0源码解析3:react-reconciler包
时间:2023-06-08 13:20:03
此包主要复制创建fiber
并且在状态更新时找到变化的组件,并交给renderer(渲染器)
渲染。接下来,通过下面代码来解析一下,创建过程。
reconciler整体流程
render
:beginWork
:主要是根据当前fiberNode
创建子fiberNode
以及在update
时标记placement(新增、移动)
、ChildDeletion(删除)
completeWork
: 在mount
时构建离屏Dom Tree
, 初始化属性,在update
时标记Update(属性更新)
、执行flags冒泡
commit
:
源码解析
业务代码
import ReactDOM from 'react-dom/client'
import App from './App'
const root = ReactDOM.createRoot(document.querySelector('#root') as HTMLDivElement)
root.render(<App />)
createRoot
export function createRoot(
container: Element | Document | DocumentFragment,
options?: CreateRootOptions,
): RootType {
// 创建fiber root
const root = createContainer(
container,
ConcurrentRoot,
null,
isStrictMode,
concurrentUpdatesByDefaultOverride,
identifierPrefix,
onRecoverableError,
transitionCallbacks,
);
// 注册事件
listenToAllSupportedEvents(rootContainerElement);
// 创建ReactDOMRoot的实例,实例上挂载了两个函数: render,unmount
return new ReactDOMRoot(root);
}
其中,createContainer
是在packages/react-reconciler/src/ReactFiberReconciler.js
中。
createContainer
export function createContainer(
containerInfo: Container,
tag: RootTag,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
isStrictMode: boolean,
concurrentUpdatesByDefaultOverride: null | boolean,
identifierPrefix: string,
onRecoverableError: (error: mixed) => void,
transitionCallbacks: null | TransitionTracingCallbacks,
): OpaqueRoot {
const hydrate = false;
const initialChildren = null;
return createFiberRoot(
containerInfo,
tag,
hydrate,
initialChildren,
hydrationCallbacks,
isStrictMode,
concurrentUpdatesByDefaultOverride,
identifierPrefix,
onRecoverableError,
transitionCallbacks,
);
}
createContainer
中又调用了packages/react-reconciler/src/ReactFiberRoot.js
的createFiberRoot
createFiberRoot
fiber采用的是"双缓存"技术来更新DOM树的。屏幕绘制的内容对应的fiber树叫
current Fiber
,在内存中构建的树叫:workInProgress Fiber
export function createFiberRoot(
containerInfo: Container,
tag: RootTag,
hydrate: boolean,
initialChildren: ReactNodeList,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
isStrictMode: boolean,
concurrentUpdatesByDefaultOverride: null | boolean,
identifierPrefix: string,
onRecoverableError: null | ((error: mixed) => void),
transitionCallbacks: null | TransitionTracingCallbacks,
): FiberRoot {
// 实例化fiber root node
const root: FiberRoot = (new FiberRootNode(
containerInfo,
tag,
hydrate,
identifierPrefix,
onRecoverableError,
): any);
// 创建host root fiber,和fiberRootNode进行双向引用
const uninitializedFiber = createHostRootFiber(
tag,
isStrictMode,
concurrentUpdatesByDefaultOverride,
);
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;
// 初始化更新队列
initializeUpdateQueue(uninitializedFiber);
return root;
}
createFiberRoot
函数主要是:实例化FiberRootNode
、创建HostRootFiber并和FiberRootNode相关联
。
创建fiberRootNode
function FiberRootNode(
this: $FlowFixMe,
containerInfo: any,
tag,
hydrate: any,
identifierPrefix: any,
onRecoverableError: any,
) {
// Root类型
// export type RootTag = 0 | 1;
// export const LegacyRoot = 0;
// export const ConcurrentRoot = 1;
// createRoot传入的是ConcurrentRoot
this.tag = tag;
// DOM容器节点
this.containerInfo = containerInfo;
this.pendingChildren = null;
// fiberNode
this.current = null;
this.pingCache = null;
this.finishedWork = null;
this.timeoutHandle = noTimeout;
this.cancelPendingCommit = null;
this.context = null;
this.pendingContext = null;
this.next = null;
this.callbackNode = null;
this.callbackPriority = NoLane;
this.expirationTimes = createLaneMap(NoTimestamp);
this.pendingLanes = NoLanes;
this.suspendedLanes = NoLanes;
this.pingedLanes = NoLanes;
this.expiredLanes = NoLanes;
this.mutableReadLanes = NoLanes;
this.finishedLanes = NoLanes;
this.errorRecoveryDisabledLanes = NoLanes;
this.entangledLanes = NoLanes;
this.entanglements = createLaneMap(NoLanes);
this.hiddenUpdates = createLaneMap(null);
this.identifierPrefix = identifierPrefix;
this.onRecoverableError = onRecoverableError;
if (enableCache) {
this.pooledCache = null;
this.pooledCacheLanes = NoLanes;
}
if (supportsHydration) {
this.mutableSourceEagerHydrationData = null;
}
if (enableSuspenseCallback) {
this.hydrationCallbacks = null;
}
this.incompleteTransitions = new Map();
if (enableTransitionTracing) {
this.transitionCallbacks = null;
const transitionLanesMap = (this.transitionLanes = []);
for (let i = 0; i < TotalLanes; i++) {
transitionLanesMap.push(null);
}
}
if (enableProfilerTimer && enableProfilerCommitHooks) {
this.effectDuration = 0;
this.passiveEffectDuration = 0;
}
if (enableUpdaterTracking) {
this.memoizedUpdaters = new Set();
const pendingUpdatersLaneMap = (this.pendingUpdatersLaneMap = []);
for (let i = 0; i < TotalLanes; i++) {
pendingUpdatersLaneMap.push(new Set());
}
}
}
创建hostRootFiber
createHostRootFiber
最终是实例化FiberNode
对象
function FiberNode(
this: $FlowFixMe,
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
// Instance
this.tag = tag;
this.key = key;
this.elementType = null;
this.type = null;
this.stateNode = null;
// Fiber
// 父节点
this.return = null;
// 子节点
this.child = null;
// 兄弟节点
this.sibling = null;
this.index = 0;
this.ref = null;
this.refCleanup = null;
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;
this.mode = mode;
// Effects
this.flags = NoFlags;
this.subtreeFlags = NoFlags;
this.deletions = null;
this.lanes = NoLanes;
this.childLanes = NoLanes;
this.alternate = null;
}
执行完createRoot
之后,就创建了一个初始的fiberRoot
和fiberNode
。然后就是new ReactDOMRoot
ReactDOMRoot.render
ReactDOMRoot.render
的方法最终调用的是reconciler
的updateContainer
export function updateContainer(
element: ReactNodeList,
container: OpaqueRoot,
parentComponent: ?React$Component<any, any>,
callback: ?Function,
): Lane {
const current = container.current;
// 获取lane(更新优先级),是一个二进制数字
const lane = requestUpdateLane(current);
if (enableSchedulingProfiler) {
markRenderScheduled(lane);
}
// 获取上下午
const context = getContextForSubtree(parentComponent);
if (container.context === null) {
container.context = context;
} else {
container.pendingContext = context;
}
// 创建update对象
const update = createUpdate(lane);
// 将组件设置到update对象上
update.payload = {element};
callback = callback === undefined ? null : callback;
if (callback !== null) {
update.callback = callback;
}
// 将update对象推入更新队列中,并根据lane找到要更新队列中的位置
const root = enqueueUpdate(current, update, lane);
if (root !== null) {
// 调度更新
scheduleUpdateOnFiber(root, current, lane);
entangleTransitions(root, current, lane);
}
return lane;
}
lane(车道)
:位数越靠右则优先级越高
变量 | 值 | 含义 |
---|---|---|
TotalLanes | 31 | 所有车道 |
NoLanes/NoLane | 0b0000000000000000000000000000000 | 无可用车道 |
SyncHydrationLane | 0b0000000000000000000000000000001 | 同步Hydration车道 |
SyncLane | 0b0000000000000000000000000000010 | 同步车道 |
InputContinuousHydrationLane | 0b0000000000000000000000000000100 | 连续输入Hydration车道 |
InputContinuousLane | 0b0000000000000000000000000001000 | 连续输入车道 |
DefaultHydrationLane | 0b0000000000000000000000000010000 | 默认Hydration车道 |
DefaultLane | 0b0000000000000000000000000100000 | 默认车道 |
TransitionHydrationLane | 0b0000000000000000000000001000000 | 过渡Hydration车道 |
TransitionLanes | 0b0000000000000000000000000001000 | 过渡车道组,包含 TransitionLane1 ~ TransitionLane16 |
RetryLanes | 0b0000000000000000000000000001000 | 重试车道组,包含RetryLane1~RetryLane5 |
SomeRetryLane | RetryLane1 | RetryLane1 又称为 SomeRetryLane |
SelectiveHydrationLane | 0b0001000000000000000000000000000 | 选择性的 Hydration 车道 |
NonIdleLanes | 0b0001111111111111111111111111111 | 除IdleLane和IdleHydrationLane以外的所有车道 |
IdleHydrationLane | 0b0010000000000000000000000000000 | 闲置Hydration车道 |
IdleLane | 0b0100000000000000000000000000000 | 闲置车道 |
OffscreenLane | 0b1000000000000000000000000000000 | 离屏车道 |