React Fiber 协调器
由于文件是线性结构,且较长,直接按功能进行线性分析。 (未导出的模块可能并非按源代码结构进行的布局)
一、作用
二、 查找宿主实例
备注
getInstance()由宿主环境提供findCurrentHostFiber()由 ReactFiberTreeReflection#findCurrentHostFiber 实现getPublicInstance()由宿主环境提供
function findHostInstance(component: Object): PublicInstance | null {
// 获取实例(方法来自于 shared )
const fiber = getInstance(component);
// 获取的实例为空则抛出错误
if (fiber === undefined) {
if (typeof component.render === 'function') {
throw new Error('Unable to find node on an unmounted component.');
} else {
const keys = Object.keys(component).join(',');
throw new Error(
`Argument appears to not be a ReactComponent. Keys: ${keys}`,
);
}
}
// 查找当前宿主的 Fiber
const hostFiber = findCurrentHostFiber(fiber);
if (hostFiber === null) {
return null;
}
// 该方法由环境自行实现(在各平台各自的 renderer 中实现)
return getPublicInstance(hostFiber.stateNode);
}
三、查找宿主实例(带警告)
备注
getInstance()由宿主环境提供findCurrentHostFiber()由 ReactFiberTreeReflection#findCurrentHostFiber 实现getComponentNameFromFiber()由 getComponentNameFromFiber 实现runWithFiberInDEV()由 ReactCurrentFiber#runWithFiberInDEV 实现getPublicInstance()由宿主环境提供
function findHostInstanceWithWarning(
component: Object,
methodName: string,
): PublicInstance | null {
if (__DEV__) {
// 该方法在 shared 中实现
const fiber = getInstance(component);
if (fiber === undefined) {
if (typeof component.render === 'function') {
throw new Error('Unable to find node on an unmounted component.');
} else {
const keys = Object.keys(component).join(',');
throw new Error(
`Argument appears to not be a ReactComponent. Keys: ${keys}`,
);
}
}
// 查找当前宿主 Fiber
const hostFiber = findCurrentHostFiber(fiber);
if (hostFiber === null) {
return null;
}
if (hostFiber.mode & StrictLegacyMode) {
// 文件 getComponentNameFromFiber 实现该方法
const componentName = getComponentNameFromFiber(fiber) || 'Component';
if (!didWarnAboutFindNodeInStrictMode[componentName]) {
didWarnAboutFindNodeInStrictMode[componentName] = true;
// 文件 ReactCurrentFiber 中实现该方法
runWithFiberInDEV(hostFiber, () => {
if (fiber.mode & StrictLegacyMode) {
console.error(
'%s is deprecated in StrictMode. ' +
'%s was passed an instance of %s which is inside StrictMode. ' +
'Instead, add a ref directly to the element you want to reference. ' +
'Learn more about using refs safely here: ' +
'https://react.dev/link/strict-mode-find-node',
methodName,
methodName,
componentName,
);
} else {
console.error(
'%s is deprecated in StrictMode. ' +
'%s was passed an instance of %s which renders StrictMode children. ' +
'Instead, add a ref directly to the element you want to reference. ' +
'Learn more about using refs safely here: ' +
'https://react.dev/link/strict-mode-find-node',
methodName,
methodName,
componentName,
);
}
});
}
}
// 该方法由环境自行实现(在各平台各自的 renderer 中实现)
return getPublicInstance(hostFiber.stateNode);
}
// 一: 查找宿主实例
return findHostInstance(component);
}
四、创建容器
创建容器,貌似是入口
信息
createFiberRoot()由 ReactFiberRoot#createFiberRoot 实现registerDefaultIndicator()由 ReactFiberAsyncAction#registerDefaultIndicator 实现
export function createContainer(
containerInfo: Container,
tag: RootTag,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
isStrictMode: boolean,
// TODO: Remove `concurrentUpdatesByDefaultOverride`. It is now ignored.
// 待办:移除 `concurrentUpdatesByDefaultOverride`。它现在已被忽略。
concurrentUpdatesByDefaultOverride: null | boolean,
identifierPrefix: string,
onUncaughtError: (
error: mixed,
// errorInfo: { +componentStack?: ?string },
errorInfo: { componentStack?: string },
) => void,
onCaughtError: (
error: mixed,
errorInfo: {
// +componentStack?: ?string;
componentStack?: string;
// +errorBoundary?: component(...props: any),
errorBoundary?: Component;
},
) => void,
onRecoverableError: (
error: mixed,
// errorInfo: { +componentStack?: ?string },
errorInfo: { componentStack?: string },
) => void,
onDefaultTransitionIndicator: () => void | (() => void),
transitionCallbacks: null | TransitionTracingCallbacks,
): OpaqueRoot {
const hydrate = false;
const initialChildren = null;
const root = createFiberRoot(
containerInfo,
tag,
hydrate,
initialChildren,
hydrationCallbacks,
isStrictMode,
identifierPrefix,
null,
onUncaughtError,
onCaughtError,
onRecoverableError,
onDefaultTransitionIndicator,
transitionCallbacks,
);
registerDefaultIndicator(onDefaultTransitionIndicator);
return root;
}
五、创建水合容器
备注
createFiberRoot()由 ReactFiberRoot#createFiberRoot 实现registerDefaultIndicator()由 ReactFiberAsyncAction#registerDefaultIndicator 实现requestUpdateLane()由 ReactFiberWorkLoop#requestUpdateLane 实现getBumpedLaneForHydrationByLane()由 ReactFiberLane#getBumpedLaneForHydrationByLane 实现createUpdate()由 ReactFiberClassUpdateQueue#createUpdate 实现enqueueUpdate()由 ReactFiberClassUpdateQueue#enqueueUpdate 实现startUpdateTimerByLane()由 ReactProfilerTimer#startUpdateTimerByLane 实现scheduleInitialHydrationOnRoot()由 ReactFiberWorkLoop#scheduleInitialHydrationOnRoot 实现
export function createHydrationContainer(
initialChildren: ReactNodeList,
// TODO: Remove `callback` when we delete legacy mode.
callback: ?Function,
containerInfo: Container,
tag: RootTag,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
isStrictMode: boolean,
// TODO: Remove `concurrentUpdatesByDefaultOverride`. It is now ignored.
concurrentUpdatesByDefaultOverride: null | boolean,
identifierPrefix: string,
onUncaughtError: (
error: mixed,
// errorInfo: {+componentStack?: ?string},
errorInfo: { componentStack?: ?string },
) => void,
onCaughtError: (
error: mixed,
errorInfo: {
// +componentStack?: ?string,
componentStack?: ?string;
// +errorBoundary?: ?component(...props: any),
errorBoundary?: Component;
},
) => void,
onRecoverableError: (
error: mixed,
// errorInfo: {+componentStack?: ?string},
errorInfo: { componentStack?: ?string },
) => void,
onDefaultTransitionIndicator: () => void | (() => void),
transitionCallbacks: null | TransitionTracingCallbacks,
formState: ReactFormState<any, any> | null,
): OpaqueRoot {
const hydrate = true;
const root = createFiberRoot(
containerInfo,
tag,
hydrate,
initialChildren,
hydrationCallbacks,
isStrictMode,
identifierPrefix,
formState,
onUncaughtError,
onCaughtError,
onRecoverableError,
onDefaultTransitionIndicator,
transitionCallbacks,
);
registerDefaultIndicator(onDefaultTransitionIndicator);
// TODO: Move this to FiberRoot constructor
root.context = getContextForSubtree(null);
// Schedule the initial render. In a hydration root, this is different from
// a regular update because the initial render must match was was rendered
// on the server.
// NOTE: This update intentionally doesn't have a payload. We're only using
// the update to schedule work on the root fiber (and, for legacy roots, to
// enqueue the callback if one is provided).
const current = root.current;
let lane = requestUpdateLane(current);
if (enableHydrationLaneScheduling) {
lane = getBumpedLaneForHydrationByLane(lane);
}
const update = createUpdate(lane);
update.callback =
callback !== undefined && callback !== null ? callback : null;
enqueueUpdate(current, update, lane);
startUpdateTimerByLane(lane, 'hydrateRoot()', null);
scheduleInitialHydrationOnRoot(root, lane);
return root;
}
六、更新容器
备注
requestUpdateLane()由 ReactFiberWorkLoop#requestUpdateLane 实现
export function updateContainer(
element: ReactNodeList,
container: OpaqueRoot,
// parentComponent: ?component(...props: any),
parentComponent: ?Component,
callback: ?Function,
): Lane {
const current = container.current;
const lane = requestUpdateLane(current);
updateContainerImpl(
current,
lane,
element,
container,
parentComponent,
callback,
);
return lane;
}
七、更新容器同步
备注
flushPendingEffects()由 ReactFiberWorkLoop#flushPendingEffects 实现
export function updateContainerSync(
element: ReactNodeList,
container: OpaqueRoot,
// parentComponent: ?component(...props: any),
parentComponent: ?Component,
callback: ?Function,
): Lane {
if (!disableLegacyMode && container.tag === LegacyRoot) {
flushPendingEffects();
}
const current = container.current;
updateContainerImpl(
current,
SyncLane,
element,
container,
parentComponent,
callback,
);
return SyncLane;
}
八、获取公共根实例
备注
getPublicInstance()由宿主环境提供
export function getPublicRootInstance(
container: OpaqueRoot,
// ): component(...props: any) | PublicInstance | null {
): Component | PublicInstance | null {
const containerFiber = container.current;
if (!containerFiber.child) {
return null;
}
switch (containerFiber.child.tag) {
case HostSingleton:
case HostComponent:
return getPublicInstance(containerFiber.child.stateNode);
default:
return containerFiber.child.stateNode;
}
}
九、尝试同步水合
备注
isRootDehydrated()由 ReactFiberShellHydration#isRootDehydrated 实现getHighestPriorityPendingLanes()由 ReactFiberLane#getHighestPriorityPendingLanes 实现flushRoot()由 ReactFiberWorkLoop#flushRoot 实现enqueueConcurrentRenderForLane()由 ReactFiberConcurrentUpdates#enqueueConcurrentRenderForLane 实现scheduleUpdateOnFiber()由 ReactFiberWorkLoop#scheduleUpdateOnFiber 实现
export function attemptSynchronousHydration(fiber: Fiber): void {
switch (fiber.tag) {
case HostRoot: {
const root: FiberRoot = fiber.stateNode;
if (isRootDehydrated(root)) {
// Flush the first scheduled "update".
// 刷新第一次计划的“更新”。
const lanes = getHighestPriorityPendingLanes(root);
flushRoot(root, lanes);
}
break;
}
case ActivityComponent:
case SuspenseComponent: {
const root = enqueueConcurrentRenderForLane(fiber, SyncLane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, SyncLane);
}
flushSyncWork();
// If we're still blocked after this, we need to increase
// the priority of any promises resolving within this
// boundary so that they next attempt also has higher pri.
//
// 如果在此之后我们仍被阻塞,我们需要提高在此边界内解决的任何 Promise 的优先级,
// 这样它们下一次尝试时的优先级也会更高。
const retryLane = SyncLane;
markRetryLaneIfNotHydrated(fiber, retryLane);
break;
}
}
}
十、尝试持续水合
备注
enqueueConcurrentRenderForLane()由 ReactFiberConcurrentUpdates#enqueueConcurrentRenderForLane 实现scheduleUpdateOnFiber()由 ReactFiberWorkLoop#scheduleUpdateOnFiber 实现
export function attemptContinuousHydration(fiber: Fiber): void {
if (fiber.tag !== SuspenseComponent && fiber.tag !== ActivityComponent) {
// We ignore HostRoots here because we can't increase
// their priority and they should not suspend on I/O,
// since you have to wrap anything that might suspend in
// Suspense.
//
// 我们在这里忽略 HostRoots,因为我们无法提高它们的优先级,并且它们不应该在 I/O 上挂起,
// 因为你必须将可能挂起的任何内容包装在 Suspense 中。
return;
}
const lane = SelectiveHydrationLane;
const root = enqueueConcurrentRenderForLane(fiber, lane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, lane);
}
markRetryLaneIfNotHydrated(fiber, lane);
}
十一、在当前优先级尝试水合
备注
requestUpdateLane()由 ReactFiberWorkLoop#requestUpdateLane 实现getBumpedLaneForHydrationByLane()由 ReactFiberLane#getBumpedLaneForHydrationByLane 实现enqueueConcurrentRenderForLane()由 ReactFiberConcurrentUpdates#enqueueConcurrentRenderForLane 实现scheduleUpdateOnFiber()由 ReactFiberWorkLoop#scheduleUpdateOnFiber 实现
export function attemptHydrationAtCurrentPriority(fiber: Fiber): void {
if (fiber.tag !== SuspenseComponent && fiber.tag !== ActivityComponent) {
// We ignore HostRoots here because we can't increase
// their priority other than synchronously flush it.
// 我们在这里忽略 HostRoots,因为除非同步刷新,否则无法提高它们的优先级。
return;
}
let lane = requestUpdateLane(fiber);
if (enableHydrationLaneScheduling) {
lane = getBumpedLaneForHydrationByLane(lane);
}
const root = enqueueConcurrentRenderForLane(fiber, lane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, lane);
}
markRetryLaneIfNotHydrated(fiber, lane);
}
十二、查找没有门户的宿主实例
备注
findCurrentHostFiberWithNoPortals()由 ReactFiberTreeReflection#findCurrentHostFiberWithNoPortals 实现getPublicInstance()由宿主环境提供
export function findHostInstanceWithNoPortals(
fiber: Fiber,
): PublicInstance | null {
const hostFiber = findCurrentHostFiberWithNoPortals(fiber);
if (hostFiber === null) {
return null;
}
return getPublicInstance(hostFiber.stateNode);
}
十三、应出错
let shouldErrorImpl: Fiber => ?boolean = fiber => null;
export function shouldError(fiber: Fiber): ?boolean {
return shouldErrorImpl(fiber);
}
十四、应挂起
let shouldSuspendImpl = (fiber: Fiber) => false;
export function shouldSuspend(fiber: Fiber): boolean {
return shouldSuspendImpl(fiber);
}
十五、注入到开发者工具
备注
scheduleRefresh()由 ReactFiberHotReloading#scheduleRefresh 实现scheduleRoot()由 ReactFiberDevToolsHook#onScheduleRoot 实现setRefreshHandler()由 ReactFiberHotReloading#setRefreshHandler 实现injectProfilingHooks()由 ReactFiberDevToolsHook#injectProfilingHooks 实现injectInternals()由 ReactFiberDevToolsHook#injectInternals 实现
export function injectIntoDevTools(): boolean {
const internals: Object = {
// 可能稍后会添加 PROFILE。
bundleType: __DEV__ ? 1 : 0, // Might add PROFILE later.
version: rendererVersion,
rendererPackageName: rendererPackageName,
currentDispatcherRef: ReactSharedInternals,
// Enables DevTools to detect reconciler version rather than renderer version
// which may not match for third party renderers.
// 允许 DevTools 检测协调器版本而不是渲染器版本。对于第三方渲染器,两者可能不匹配。
reconcilerVersion: ReactVersion,
};
if (extraDevToolsConfig !== null) {
internals.rendererConfig = extraDevToolsConfig as RendererInspectionConfig;
}
if (__DEV__) {
internals.overrideHookState = overrideHookState;
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
internals.overrideHookStateRenamePath = overrideHookStateRenamePath;
internals.overrideProps = overrideProps;
internals.overridePropsDeletePath = overridePropsDeletePath;
internals.overridePropsRenamePath = overridePropsRenamePath;
internals.scheduleUpdate = scheduleUpdate;
internals.scheduleRetry = scheduleRetry;
internals.setErrorHandler = setErrorHandler;
internals.setSuspenseHandler = setSuspenseHandler;
// React Refresh
// React 刷新
internals.scheduleRefresh = scheduleRefresh;
internals.scheduleRoot = scheduleRoot;
internals.setRefreshHandler = setRefreshHandler;
// Enables DevTools to append owner stacks to error messages in DEV mode.
// 允许在开发模式下,DevTools 在错误消息中附加所有者堆栈。
internals.getCurrentFiber = getCurrentFiberForDevTools;
}
if (enableSchedulingProfiler) {
// Conditionally inject these hooks only if Timeline profiler is supported by this build.
// This gives DevTools a way to feature detect that isn't tied to version number
// (since profiling and timeline are controlled by different feature flags).
//
// 仅在此构建支持时间轴分析器时有条件地注入这些钩子。这为 DevTools 提供了一种不依赖版本号的功能检测方式
// (因为分析和时间轴由不同的功能标志控制)。
internals.getLaneLabelMap = getLaneLabelMap;
internals.injectProfilingHooks = injectProfilingHooks;
}
return injectInternals(internals);
}
十六、常数
1. 是否提示信息
// 是否警告关于嵌套更新
let didWarnAboutNestedUpdates: boolean;
// 是否警告在严格模式下使用 findNode
let didWarnAboutFindNodeInStrictMode: { [string]: boolean };
if (__DEV__) {
didWarnAboutNestedUpdates = false;
didWarnAboutFindNodeInStrictMode = {};
}
十七、变量
1. 应当错误实现
// let shouldErrorImpl: Fiber => ?boolean = fiber => null;
let shouldErrorImpl: (Fiber) => ?boolean = fiber => null;
2. 应挂起实现
let shouldSuspendImpl = (fiber: Fiber) => false;
3. en
备注
enqueueConcurrentRenderForLane()由 ReactFiberConcurrentUpdates#enqueueConcurrentRenderForLane 实现scheduleUpdateOnFiber()由 ReactFiberWorkLoop#scheduleUpdateOnFiber 实现
// 覆盖钩子状态
let overrideHookState = null;
// 覆盖钩子状态删除路径
let overrideHookStateDeletePath = null;
// 覆盖钩子状态重命名路径
let overrideHookStateRenamePath = null;
// 覆盖属性
let overrideProps = null;
// 覆盖属性删除路径
let overridePropsDeletePath = null;
// 覆盖属性重命名路径
let overridePropsRenamePath = null;
// 安排更新
let scheduleUpdate = null;
// 安排重试
let scheduleRetry = null;
// 设置错误处理程序
let setErrorHandler = null;
// 设置悬念处理程序
let setSuspenseHandler = null;
if (__DEV__) {
// 复制并删除(实现)
const copyWithDeleteImpl = (
obj: Object | Array<any>,
path: Array<string | number>,
index: number,
): $FlowFixMe => {
const key = path[index];
const updated = isArray(obj) ? obj.slice() : { ...obj };
if (index + 1 === path.length) {
if (isArray(updated)) {
updated.splice(key as any as number, 1);
} else {
delete updated[key];
}
return updated;
}
updated[key] = copyWithDeleteImpl(obj[key], path, index + 1);
return updated;
};
// 复制并删除
const copyWithDelete = (
obj: Object | Array<any>,
path: Array<string | number>,
): Object | Array<any> => {
return copyWithDeleteImpl(obj, path, 0);
};
// 复制并重命名(实现)
const copyWithRenameImpl = (
obj: Object | Array<any>,
oldPath: Array<string | number>,
newPath: Array<string | number>,
index: number,
): $FlowFixMe => {
const oldKey = oldPath[index];
const updated = isArray(obj) ? obj.slice() : { ...obj };
if (index + 1 === oldPath.length) {
const newKey = newPath[index];
updated[newKey] = updated[oldKey];
if (isArray(updated)) {
updated.splice(oldKey as any as number, 1);
} else {
delete updated[oldKey];
}
} else {
updated[oldKey] = copyWithRenameImpl(
obj[oldKey],
oldPath,
newPath,
index + 1,
);
}
return updated;
};
// 复制并重命名
const copyWithRename = (
obj: Object | Array<any>,
oldPath: Array<string | number>,
newPath: Array<string | number>,
): Object | Array<any> => {
if (oldPath.length !== newPath.length) {
console.warn('copyWithRename() expects paths of the same length');
return;
} else {
for (let i = 0; i < newPath.length - 1; i++) {
if (oldPath[i] !== newPath[i]) {
console.warn(
'copyWithRename() expects paths to be the same except for the deepest key',
);
return;
}
}
}
return copyWithRenameImpl(obj, oldPath, newPath, 0);
};
// 带集合的复制(实现)
const copyWithSetImpl = (
obj: Object | Array<any>,
path: Array<string | number>,
index: number,
value: any,
): $FlowFixMe => {
if (index >= path.length) {
return value;
}
const key = path[index];
const updated = isArray(obj) ? obj.slice() : { ...obj };
updated[key] = copyWithSetImpl(obj[key], path, index + 1, value);
return updated;
};
// 带集合的复制
const copyWithSet = (
obj: Object | Array<any>,
path: Array<string | number>,
value: any,
): Object | Array<any> => {
return copyWithSetImpl(obj, path, 0, value);
};
// 寻找钩子
const findHook = (fiber: Fiber, id: number) => {
// For now, the "id" of stateful hooks is just the stateful hook index.
// This may change in the future with e.g. nested hooks.
// 目前,有状态钩子的 “id” 只是有状态钩子的索引。将来可能会改变,例如在嵌套钩子的情况下。
let currentHook = fiber.memoizedState;
while (currentHook !== null && id > 0) {
currentHook = currentHook.next;
id--;
}
return currentHook;
};
// Support DevTools editable values for useState and useReducer.
// 支持 DevTools 编辑 useState 和 useReducer 的值。
overrideHookState = (
fiber: Fiber,
id: number,
path: Array<string | number>,
value: any,
) => {
const hook = findHook(fiber, id);
if (hook !== null) {
const newState = copyWithSet(hook.memoizedState, path, value);
hook.memoizedState = newState;
hook.baseState = newState;
// We aren't actually adding an update to the queue,
// because there is no update we can add for useReducer hooks that won't trigger an error.
// (There's no appropriate action type for DevTools overrides.)
// As a result though, React will see the scheduled update as a noop and bailout.
// Shallow cloning props works as a workaround for now to bypass the bailout check.
//
// 我们实际上并没有将更新添加到队列中,因为对于 useReducer 钩子,没有可以添加的更新而不会触发错误。
// (没有适合 DevTools 覆盖的操作类型。)因此,React 会将计划的更新视为无操作并跳过。
// 目前,浅复制 props 可以作为一种解决方法来绕过跳过检查。
fiber.memoizedProps = { ...fiber.memoizedProps };
const root = enqueueConcurrentRenderForLane(fiber, SyncLane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, SyncLane);
}
}
};
overrideHookStateDeletePath = (
fiber: Fiber,
id: number,
path: Array<string | number>,
) => {
const hook = findHook(fiber, id);
if (hook !== null) {
const newState = copyWithDelete(hook.memoizedState, path);
hook.memoizedState = newState;
hook.baseState = newState;
// We aren't actually adding an update to the queue,
// because there is no update we can add for useReducer hooks that won't trigger an error.
// (There's no appropriate action type for DevTools overrides.)
// As a result though, React will see the scheduled update as a noop and bailout.
// Shallow cloning props works as a workaround for now to bypass the bailout check.
//
// 我们实际上并没有将更新添加到队列中,因为对于 useReducer 钩子,没有可以添加的更新而不会触发错误。
// (没有适合 DevTools 覆盖的操作类型。)因此,React 会将计划的更新视为无操作并跳过。
// 目前,浅复制 props 可以作为一种解决方法来绕过跳过检查。
fiber.memoizedProps = { ...fiber.memoizedProps };
const root = enqueueConcurrentRenderForLane(fiber, SyncLane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, SyncLane);
}
}
};
overrideHookStateRenamePath = (
fiber: Fiber,
id: number,
oldPath: Array<string | number>,
newPath: Array<string | number>,
) => {
const hook = findHook(fiber, id);
if (hook !== null) {
const newState = copyWithRename(hook.memoizedState, oldPath, newPath);
hook.memoizedState = newState;
hook.baseState = newState;
// We aren't actually adding an update to the queue,
// because there is no update we can add for useReducer hooks that won't trigger an error.
// (There's no appropriate action type for DevTools overrides.)
// As a result though, React will see the scheduled update as a noop and bailout.
// Shallow cloning props works as a workaround for now to bypass the bailout check.
//
// 我们实际上并没有将更新添加到队列中,因为对于 useReducer 钩子,没有可以添加的更新而不会触发错误。
// (没有适合 DevTools 覆盖的操作类型。)因此,React 会将计划的更新视为无操作并跳过。
// 目前,浅复制 props 可以作为一种解决方法来绕过跳过检查。
fiber.memoizedProps = { ...fiber.memoizedProps };
const root = enqueueConcurrentRenderForLane(fiber, SyncLane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, SyncLane);
}
}
};
// Support DevTools props for function components, forwardRef, memo, host components, etc.
// 支持函数组件、forwardRef、memo、宿主组件等的 DevTools 属性
overrideProps = (fiber: Fiber, path: Array<string | number>, value: any) => {
fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value);
if (fiber.alternate) {
fiber.alternate.pendingProps = fiber.pendingProps;
}
const root = enqueueConcurrentRenderForLane(fiber, SyncLane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, SyncLane);
}
};
overridePropsDeletePath = (fiber: Fiber, path: Array<string | number>) => {
fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path);
if (fiber.alternate) {
fiber.alternate.pendingProps = fiber.pendingProps;
}
const root = enqueueConcurrentRenderForLane(fiber, SyncLane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, SyncLane);
}
};
overridePropsRenamePath = (
fiber: Fiber,
oldPath: Array<string | number>,
newPath: Array<string | number>,
) => {
fiber.pendingProps = copyWithRename(fiber.memoizedProps, oldPath, newPath);
if (fiber.alternate) {
fiber.alternate.pendingProps = fiber.pendingProps;
}
const root = enqueueConcurrentRenderForLane(fiber, SyncLane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, SyncLane);
}
};
scheduleUpdate = (fiber: Fiber) => {
const root = enqueueConcurrentRenderForLane(fiber, SyncLane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, SyncLane);
}
};
scheduleRetry = (fiber: Fiber) => {
const lane = claimNextRetryLane();
const root = enqueueConcurrentRenderForLane(fiber, lane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, lane);
}
};
setErrorHandler = (newShouldErrorImpl: (fiber: Fiber) => ?boolean) => {
shouldErrorImpl = newShouldErrorImpl;
};
setSuspenseHandler = (newShouldSuspendImpl: (fiber: Fiber) => boolean) => {
shouldSuspendImpl = newShouldSuspendImpl;
};
}
十八、工具
1. 获取子树的上下文
- 如果参数为空,则返回一个空的上下文对象(
emptyContextObject) - 参数不为空,判定上写文是否是
class组件而做了一个兼容判定,返回子树的上下文
备注
getInstance()由宿主环境提供findCurrentUnmaskedContext()由 ReactFiberLegacyContext#findCurrentUnmaskedContext 实现isLegacyContextProvider()由 ReactTypeOfMode#StrictLegacyMode 实现processChildContext()由 ReactFiberLegacyContext#processChildContext 实现
function getContextForSubtree(
// 父组件 component(...props: any)
parentComponent?: Component,
): Object {
if (!parentComponent) {
return emptyContextObject;
}
const fiber = getInstance(parentComponent);
// 查找当前未屏蔽的上下文作为当前父元素的上下文
const parentContext = findCurrentUnmaskedContext(fiber);
if (fiber.tag === ClassComponent) {
const Component = fiber.type;
// 旧的遗留上下文提供者(即旧的 class 组件)
if (isLegacyContextProvider(Component)) {
// 返回兼容的父元素上下文
return processChildContext(fiber, Component, parentContext);
}
}
return parentContext;
}
2. 更新容器(实现)
备注
onScheduleRoot()由 ReactFiberDevToolsHook#onScheduleRoot 实现markRenderScheduled()由 ReactFiberDevToolsHook#markRenderScheduled 实现getComponentNameFromFiber()由宿主环境提供createUpdate()由 ReactFiberClassUpdateQueue#createUpdate 实现enqueueUpdate()由 ReactFiberClassUpdateQueue#enqueueUpdate 实现startUpdateTimerByLane()由 ReactProfilerTimer#startUpdateTimerByLane 实现scheduleUpdateOnFiber()由 ReactFiberWorkLoop#scheduleUpdateOnFiber 实现entangleTransitions()由 ReactFiberClassUpdateQueue#entangleTransitions 实现
function updateContainerImpl(
rootFiber: Fiber,
lane: Lane,
element: ReactNodeList,
container: OpaqueRoot,
// parentComponent: ?component(...props: any),
parentComponent: ?Component,
callback: ?Function,
): void {
if (__DEV__) {
onScheduleRoot(container, element);
}
if (enableSchedulingProfiler) {
markRenderScheduled(lane);
}
const context = getContextForSubtree(parentComponent);
if (container.context === null) {
container.context = context;
} else {
container.pendingContext = context;
}
if (__DEV__) {
if (
ReactCurrentFiberIsRendering &&
ReactCurrentFiberCurrent !== null &&
!didWarnAboutNestedUpdates
) {
didWarnAboutNestedUpdates = true;
console.error(
'Render methods should be a pure function of props and state; ' +
'triggering nested component updates from render is not allowed. ' +
'If necessary, trigger nested updates in componentDidUpdate.\n\n' +
'Check the render method of %s.',
getComponentNameFromFiber(ReactCurrentFiberCurrent) || 'Unknown',
);
}
}
const update = createUpdate(lane);
// Caution: React DevTools currently depends on this property
// being called "element".
// 注意:React 开发者工具目前依赖于该属性名称为“element”。
update.payload = { element };
callback = callback === undefined ? null : callback;
if (callback !== null) {
if (__DEV__) {
if (typeof callback !== 'function') {
console.error(
'Expected the last optional `callback` argument to be a ' +
'function. Instead received: %s.',
callback,
);
}
}
update.callback = callback;
}
const root = enqueueUpdate(rootFiber, update, lane);
if (root !== null) {
startUpdateTimerByLane(lane, 'root.render()', null);
scheduleUpdateOnFiber(root, rootFiber, lane);
entangleTransitions(root, rootFiber, lane);
}
}
3. 标记重试车道(实现)
备注
higherPriorityLane()由 ReactFiberLane#higherPriorityLane 实现
function markRetryLaneImpl(fiber: Fiber, retryLane: Lane) {
const suspenseState: null | SuspenseState | ActivityState =
fiber.memoizedState;
if (suspenseState !== null && suspenseState.dehydrated !== null) {
suspenseState.retryLane = higherPriorityLane(
suspenseState.retryLane,
retryLane,
);
}
}
4. 如果水合失败则标记重试车道
// Increases the priority of thenables when they resolve within this boundary.
// 当可等待对象在此边界内解析时,增加其优先级。
function markRetryLaneIfNotHydrated(fiber: Fiber, retryLane: Lane) {
markRetryLaneImpl(fiber, retryLane);
const alternate = fiber.alternate;
if (alternate) {
markRetryLaneImpl(alternate, retryLane);
}
}
5. 获取当前开发工具用的 Fiber
function getCurrentFiberForDevTools() {
return ReactCurrentFiberCurrent;
}
6. 获取车道标签映射
备注
getLabelForLane()由宿主环境提供
function getLaneLabelMap(): Map<Lane, string> | null {
if (enableSchedulingProfiler) {
const map: Map<Lane, string> = new Map();
let lane = 1;
for (let index = 0; index < TotalLanes; index++) {
const label = ((getLabelForLane(lane): any): string);
map.set(lane, label);
lane *= 2;
}
return map;
} else {
return null;
}
}
十九、转导
- 从 './ReactPortal' 转导了
createPortal(): ReactPortal#createPortal
- 从 './ReactTestSelectors' 转导了
createComponentSelector(): ReactTestSelectors#createComponentSelectorcreateHasPseudoClassSelector(): ReactTestSelectors#createHasPseudoClassSelectorcreateRoleSelector(): ReactTestSelectors#createRoleSelectorcreateTestNameSelector(): ReactTestSelectors#createTextSelectorcreateTextSelector(): ReactTestSelectors#createTextSelectorgetFindAllNodesFailureDescription(): ReactTestSelectors#getFindAllNodesFailureDescriptionfindAllNodes(): ReactTestSelectors#findAllNodesfindBoundingRects(): ReactTestSelectors#findBoundingRectsfocusWithin(): ReactTestSelectors#focusWithinobserveVisibleRects(): ReactTestSelectors#observeVisibleRects
- 从 './ReactFiberHooks' 转导了
startHostTransition(): ReactFiberHooks#startHostTransition
- 从 './ReactFiberErrorLogger' 转导了
defaultOnUncaughtError(): ReactFiberErrorLogger#defaultOnUncaughtErrordefaultOnCaughtError(): ReactFiberErrorLogger#defaultOnCaughtErrordefaultOnRecoverableError(): ReactFiberErrorLogger#defaultOnRecoverableError
- 从 './ReactFiberWorkLoop' 转导了
batchedUpdates(): ReactFiberWorkLoop#batchedUpdatesdeferredUpdates(): ReactFiberWorkLoop#deferredUpdatesdiscreteUpdates(): ReactFiberWorkLoop#discreteUpdatesflushSyncFromReconciler(): ReactFiberWorkLoop#flushSyncFromReconcilerflushSyncWork(): ReactFiberWorkLoop#flushSyncWorkisAlreadyRendering(): ReactFiberWorkLoop#isAlreadyRenderingflushPassiveEffects(): ReactFiberWorkLoop#flushPendingEffects