React Fiber
Fiber 是 React Reconciler 的核心抽象。
一、作用
二、组件类型判定
1. 是简单函数组件
export function isSimpleFunctionComponent(type: any): boolean {
return (
typeof type === 'function' &&
!shouldConstruct(type) &&
type.defaultProps === undefined
);
}
2. 是函数式类组件
export function isFunctionClassComponent(
type: (...args: Array<any>) => mixed,
): boolean {
return shouldConstruct(type);
}
三、进行中
1. 创建进行中的工作
构建备用的的渲染的工作树,非当前实际渲染的状态树
信息
resolveFunctionForHotReloading()由 ReactFiberHotReloading#resolveFunctionForHotReloading 实现resolveClassForHotReloading()由 ReactFiberHotReloading#resolveClassForHotReloading 实现resolveForwardRefForHotReloading()由 ReactFiberHotReloading#resolveForwardRefForHotReloading 实现
// This is used to create an alternate fiber to do work on.
// 这用于创建一个备用 fiber 来执行工作。
export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
let workInProgress = current.alternate;
if (workInProgress === null) {
// We use a double buffering pooling technique because we know that we'll
// only ever need at most two versions of a tree. We pool the "other" unused
// node that we're free to reuse. This is lazily created to avoid allocating
// extra objects for things that are never updated. It also allow us to
// reclaim the extra memory if needed.
//
// 我们使用双缓冲池技术,因为我们知道最多只需要两棵树的版本。
// 我们会池化“其他”的未使用节点,以便可以重用。
// 这是懒创建的,以避免为从未更新的对象分配额外的资源。
// 它还允许我们在需要时回收额外的内存。
workInProgress = createFiber(
current.tag,
pendingProps,
current.key,
current.mode,
);
workInProgress.elementType = current.elementType;
workInProgress.type = current.type;
workInProgress.stateNode = current.stateNode;
if (__DEV__) {
// DEV-only fields
// 仅供开发使用的字段
workInProgress._debugOwner = current._debugOwner;
workInProgress._debugStack = current._debugStack;
workInProgress._debugTask = current._debugTask;
workInProgress._debugHookTypes = current._debugHookTypes;
}
workInProgress.alternate = current;
current.alternate = workInProgress;
} else {
workInProgress.pendingProps = pendingProps;
// Needed because Blocks store data on type.
// 需要,因为块会根据类型存储数据。
workInProgress.type = current.type;
// We already have an alternate.
// Reset the effect tag.
// 我们已经有一个替代方案。
// 重置效果标签。
workInProgress.flags = NoFlags;
// The effects are no longer valid.
// 这些效果不再有效。
workInProgress.subtreeFlags = NoFlags;
workInProgress.deletions = null;
if (enableOptimisticKey) {
// For optimistic keys, the Fibers can have different keys if one is optimistic
// and the other one is filled in.
// 对于乐观键,如果一个是乐观的而另一个已经被填充,Fiber 可以有不同的键。
workInProgress.key = current.key;
}
if (enableProfilerTimer) {
// We intentionally reset, rather than copy, actualDuration & actualStartTime.
// This prevents time from endlessly accumulating in new commits.
// This has the downside of resetting values for different priority renders,
// But works for yielding (the common case) and should support resuming.
//
// 我们故意重置,而不是复制 actualDuration 和 actualStartTime。
// 这样可以防止时间在新的提交中无休止地累积。
// 这样做的缺点是会重置不同优先级渲染的值,
// 但对于让步情况(常见情况)有效,并且应该支持继续执行。
workInProgress.actualDuration = -0;
workInProgress.actualStartTime = -1.1;
}
}
// Reset all effects except static ones.
// Static effects are not specific to a render.
//
// 重置所有效果,静态效果除外。
// 静态效果与渲染无关。
workInProgress.flags = current.flags & StaticMask;
workInProgress.childLanes = current.childLanes;
workInProgress.lanes = current.lanes;
workInProgress.child = current.child;
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
// Clone the dependencies object. This is mutated during the render phase, so
// it cannot be shared with the current fiber.
//
// 克隆 dependencies 对象。该对象在渲染阶段会被修改,
// 因此不能与当前 fiber 共享。
const currentDependencies = current.dependencies;
workInProgress.dependencies =
currentDependencies === null
? null
: __DEV__
? {
lanes: currentDependencies.lanes,
firstContext: currentDependencies.firstContext,
_debugThenableState: currentDependencies._debugThenableState,
}
: {
lanes: currentDependencies.lanes,
firstContext: currentDependencies.firstContext,
};
// These will be overridden during the parent's reconciliation
// 这些将在父组件的协调过程中被覆盖
workInProgress.sibling = current.sibling;
workInProgress.index = current.index;
workInProgress.ref = current.ref;
workInProgress.refCleanup = current.refCleanup;
if (enableProfilerTimer) {
workInProgress.selfBaseDuration = current.selfBaseDuration;
workInProgress.treeBaseDuration = current.treeBaseDuration;
}
if (__DEV__) {
workInProgress._debugInfo = current._debugInfo;
workInProgress._debugNeedsRemount = current._debugNeedsRemount;
switch (workInProgress.tag) {
case FunctionComponent:
case SimpleMemoComponent:
workInProgress.type = resolveFunctionForHotReloading(current.type);
break;
case ClassComponent:
workInProgress.type = resolveClassForHotReloading(current.type);
break;
case ForwardRef:
workInProgress.type = resolveForwardRefForHotReloading(current.type);
break;
default:
break;
}
}
return workInProgress;
}
2. 重置进行中的工作
// Used to reuse a Fiber for a second pass.
// 用于将一个 Fiber 复用在第二次遍历中。
export function resetWorkInProgress(
workInProgress: Fiber,
renderLanes: Lanes,
): Fiber {
// This resets the Fiber to what createFiber or createWorkInProgress would
// have set the values to before during the first pass. Ideally this wouldn't
// be necessary but unfortunately many code paths reads from the workInProgress
// when they should be reading from current and writing to workInProgress.
//
// 这会将 Fiber 重置为 createFiber 或 createWorkInProgress 在第一次遍历时设置的值。
// 理想情况下,这本不应该是必要的,但不幸的是,许多代码路径在本应从 current 读取并写入
// workInProgress 时,却读取了 workInProgress。
// We assume pendingProps, index, key, ref, return are still untouched to
// avoid doing another reconciliation.
//
// 我们假设 pendingProps、index、key、ref、return 仍然保持不变,以避免进行另一次协调。
// Reset the effect flags but keep any Placement tags, since that's something
// that child fiber is setting, not the reconciliation.
//
// 重置效果标志,但保留任何 Placement 标签,
// 因为这是子 Fiber 设置的,而不是协调过程设置的。
workInProgress.flags &= StaticMask | Placement;
// The effects are no longer valid.
// 这些效果不再有效。
const current = workInProgress.alternate;
if (current === null) {
// Reset to createFiber's initial values.
// 重置为 createFiber 的初始值。
workInProgress.childLanes = NoLanes;
workInProgress.lanes = renderLanes;
workInProgress.child = null;
workInProgress.subtreeFlags = NoFlags;
workInProgress.memoizedProps = null;
workInProgress.memoizedState = null;
workInProgress.updateQueue = null;
workInProgress.dependencies = null;
workInProgress.stateNode = null;
if (enableProfilerTimer) {
// Note: We don't reset the actualTime counts. It's useful to accumulate
// actual time across multiple render passes.
// 注意:我们不会重置 actualTime 计数。
// 这对于在多次渲染过程中累积实际时间很有用。
workInProgress.selfBaseDuration = 0;
workInProgress.treeBaseDuration = 0;
}
} else {
// Reset to the cloned values that createWorkInProgress would've.
// 重置为 createWorkInProgress 会创建的克隆值。
workInProgress.childLanes = current.childLanes;
workInProgress.lanes = current.lanes;
workInProgress.child = current.child;
workInProgress.subtreeFlags = NoFlags;
workInProgress.deletions = null;
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
// Needed because Blocks store data on type.
// 需要,因为块会根据类型存储数据。
// TODO: Blocks don't exist anymore. Do we still need this?
// 待办事项:区块不再存在。我们还需要这个吗?
workInProgress.type = current.type;
if (enableOptimisticKey) {
// For optimistic keys, the Fibers can have different keys if one is optimistic
// and the other one is filled in.
// 对于乐观键,如果一个是乐观的而另一个已经被填充,Fiber 可以有不同的键。
workInProgress.key = current.key;
}
// Clone the dependencies object. This is mutated during the render phase, so
// it cannot be shared with the current fiber.
//
// 克隆依赖对象。它会在渲染阶段被修改,
// 因此不能与当前 fiber 共享。
const currentDependencies = current.dependencies;
workInProgress.dependencies =
currentDependencies === null
? null
: __DEV__
? {
lanes: currentDependencies.lanes,
firstContext: currentDependencies.firstContext,
_debugThenableState: currentDependencies._debugThenableState,
}
: {
lanes: currentDependencies.lanes,
firstContext: currentDependencies.firstContext,
};
if (enableProfilerTimer) {
// Note: We don't reset the actualTime counts. It's useful to accumulate
// actual time across multiple render passes.
//
// 注意:我们不会重置 actualTime 计数。这对于在多次渲染过程中累积实际时间很有用。
workInProgress.selfBaseDuration = current.selfBaseDuration;
workInProgress.treeBaseDuration = current.treeBaseDuration;
}
}
return workInProgress;
}
四、构建宿主环境根 Fiber
export function createHostRootFiber(
tag: RootTag,
isStrictMode: boolean,
): Fiber {
let mode: number;
// 禁用遗留模式 or 并发根
if (disableLegacyMode || tag === ConcurrentRoot) {
mode = ConcurrentMode;
if (isStrictMode === true) {
mode |= StrictLegacyMode | StrictEffectsMode;
}
} else {
mode = NoMode;
}
if (__DEV__ || (enableProfilerTimer && isDevToolsPresent)) {
// dev: Enable profiling instrumentation by default.
// profile: enabled if DevTools is present or subtree is wrapped in <Profiler>.
// production: disabled.
//
// 开发:默认启用性能分析工具。
// 分析:如果存在开发者工具或子树被 <Profiler> 包裹,则启用。
// 生产:禁用。
mode |= ProfileMode;
}
return createFiber(HostRoot, null, null, mode);
}
五、根据类型和属性创建 Fiber
备注
resolveClassForHotReloading()由 ReactFiberHotReloading#resolveClassForHotReloading 实现resolveFunctionForHotReloading()由 ReactFiberHotReloading#resolveFunctionForHotReloading 实现getHostContext()由 ReactFiberHostContext#getHostContext 实现isHostHoistableType()由宿主环境提供isHostSingletonType()由宿主环境提供resolveForwardRefForHotReloading()由 ReactFiberHotReloading#resolveForwardRefForHotReloading 实现getComponentNameFromType()由 shared 提供getComponentNameFromOwner()由 getComponentNameFromFiber 实现
// TODO: Get rid of this helper. Only createFiberFromElement should exist.
// 待办:去掉这个辅助函数。应该只保留 createFiberFromElement。
export function createFiberFromTypeAndProps(
type: any, // React$ElementType
key: ReactKey,
pendingProps: any,
owner: null | ReactComponentInfo | Fiber,
mode: TypeOfMode,
lanes: Lanes,
): Fiber {
let fiberTag: WorkTag = FunctionComponent;
// The resolved type is set if we know what the final type will be. I.e. it's not lazy.
// 如果我们知道最终类型,会设置已解析的类型。也就是说,它不是延迟的。
let resolvedType = type;
if (typeof type === 'function') {
if (shouldConstruct(type)) {
fiberTag = ClassComponent;
if (__DEV__) {
resolvedType = resolveClassForHotReloading(resolvedType);
}
} else {
if (__DEV__) {
resolvedType = resolveFunctionForHotReloading(resolvedType);
}
}
} else if (typeof type === 'string') {
if (supportsResources && supportsSingletons) {
const hostContext = getHostContext();
fiberTag = isHostHoistableType(type, pendingProps, hostContext)
? HostHoistable
: isHostSingletonType(type)
? HostSingleton
: HostComponent;
} else if (supportsResources) {
const hostContext = getHostContext();
fiberTag = isHostHoistableType(type, pendingProps, hostContext)
? HostHoistable
: HostComponent;
} else if (supportsSingletons) {
fiberTag = isHostSingletonType(type) ? HostSingleton : HostComponent;
} else {
fiberTag = HostComponent;
}
} else {
getTag: switch (type) {
case REACT_ACTIVITY_TYPE:
return createFiberFromActivity(pendingProps, mode, lanes, key);
case REACT_FRAGMENT_TYPE:
return createFiberFromFragment(pendingProps.children, mode, lanes, key);
case REACT_STRICT_MODE_TYPE:
fiberTag = Mode;
mode |= StrictLegacyMode;
if (disableLegacyMode || (mode & ConcurrentMode) !== NoMode) {
// Strict effects should never run on legacy roots
// 严格模式下的副作用绝不应在旧版根节点上运行
mode |= StrictEffectsMode;
}
break;
case REACT_PROFILER_TYPE:
return createFiberFromProfiler(pendingProps, mode, lanes, key);
case REACT_SUSPENSE_TYPE:
return createFiberFromSuspense(pendingProps, mode, lanes, key);
case REACT_SUSPENSE_LIST_TYPE:
return createFiberFromSuspenseList(pendingProps, mode, lanes, key);
case REACT_LEGACY_HIDDEN_TYPE:
if (enableLegacyHidden) {
return createFiberFromLegacyHidden(pendingProps, mode, lanes, key);
}
// Fall through
// 贯穿
case REACT_VIEW_TRANSITION_TYPE:
if (enableViewTransition) {
return createFiberFromViewTransition(pendingProps, mode, lanes, key);
}
// Fall through
// 贯穿
case REACT_SCOPE_TYPE:
if (enableScopeAPI) {
return createFiberFromScope(type, pendingProps, mode, lanes, key);
}
// Fall through
// 贯穿
case REACT_TRACING_MARKER_TYPE:
if (enableTransitionTracing) {
return createFiberFromTracingMarker(pendingProps, mode, lanes, key);
}
// Fall through
// 贯穿
default: {
if (typeof type === 'object' && type !== null) {
switch (type.$$typeof) {
case REACT_CONTEXT_TYPE:
fiberTag = ContextProvider;
break getTag;
case REACT_CONSUMER_TYPE:
fiberTag = ContextConsumer;
break getTag;
// Fall through
// 贯穿
case REACT_FORWARD_REF_TYPE:
fiberTag = ForwardRef;
if (__DEV__) {
resolvedType = resolveForwardRefForHotReloading(resolvedType);
}
break getTag;
case REACT_MEMO_TYPE:
fiberTag = MemoComponent;
break getTag;
case REACT_LAZY_TYPE:
fiberTag = LazyComponent;
resolvedType = null;
break getTag;
}
}
let info = '';
let typeString;
if (__DEV__) {
if (
type === undefined ||
(typeof type === 'object' &&
type !== null &&
Object.keys(type).length === 0)
) {
info +=
' You likely forgot to export your component from the file ' +
"it's defined in, or you might have mixed up default and named imports.";
}
if (type === null) {
typeString = 'null';
} else if (isArray(type)) {
typeString = 'array';
} else if (
type !== undefined &&
type.$$typeof === REACT_ELEMENT_TYPE
) {
typeString = `<${
getComponentNameFromType(type.type) || 'Unknown'
} />`;
info =
' Did you accidentally export a JSX literal instead of a component?';
} else {
typeString = typeof type;
}
const ownerName = owner ? getComponentNameFromOwner(owner) : null;
if (ownerName) {
info += '\n\nCheck the render method of `' + ownerName + '`.';
}
} else {
typeString = type === null ? 'null' : typeof type;
}
// The type is invalid but it's conceptually a child that errored and not the
// current component itself so we create a virtual child that throws in its
// begin phase. This is the same thing we do in ReactChildFiber if we throw
// but we do it here so that we can assign the debug owner and stack from the
// element itself. That way the error stack will point to the JSX callsite.
//
// 类型无效,但从概念上来说,它是一个出错的子节点,而不是当前组件本身,所以我们创建一个在其
// 开始阶段抛出异常的虚拟子节点。这与我们在 ReactChildFiber 中抛出异常时所做的相同,但我们
// 在这里这样做是为了能够从元素本身分配调试所有者和堆栈。这样,错误堆栈将指向 JSX 调用位置。
fiberTag = Throw;
pendingProps = new Error(
'Element type is invalid: expected a string (for built-in ' +
'components) or a class/function (for composite components) ' +
`but got: ${typeString}.${info}`,
);
resolvedType = null;
}
}
}
const fiber = createFiber(fiberTag, pendingProps, key, mode);
fiber.elementType = type;
fiber.type = resolvedType;
fiber.lanes = lanes;
if (__DEV__) {
fiber._debugOwner = owner;
}
return fiber;
}
六、从元素创建 Fiber
export function createFiberFromElement(
element: ReactElement,
mode: TypeOfMode,
lanes: Lanes,
): Fiber {
let owner = null;
if (__DEV__) {
owner = element._owner;
}
const type = element.type;
const key = element.key;
const pendingProps = element.props;
const fiber = createFiberFromTypeAndProps(
type,
key,
pendingProps,
owner,
mode,
lanes,
);
if (__DEV__) {
fiber._debugOwner = element._owner;
fiber._debugStack = element._debugStack;
fiber._debugTask = element._debugTask;
}
return fiber;
}
七、从片段创建Fiber
export function createFiberFromFragment(
elements: ReactFragment,
mode: TypeOfMode,
lanes: Lanes,
key: ReactKey,
): Fiber {
const fiber = createFiber(Fragment, elements, key, mode);
fiber.lanes = lanes;
return fiber;
}
八、从挂起(组件)创建 Fiber
export function createFiberFromSuspense(
pendingProps: any,
mode: TypeOfMode,
lanes: Lanes,
key: ReactKey,
): Fiber {
const fiber = createFiber(SuspenseComponent, pendingProps, key, mode);
fiber.elementType = REACT_SUSPENSE_TYPE;
fiber.lanes = lanes;
return fiber;
}
九、从挂起列表创建 Fiber
export function createFiberFromSuspenseList(
pendingProps: any,
mode: TypeOfMode,
lanes: Lanes,
key: ReactKey,
): Fiber {
const fiber = createFiber(SuspenseListComponent, pendingProps, key, mode);
fiber.elementType = REACT_SUSPENSE_LIST_TYPE;
fiber.lanes = lanes;
return fiber;
}
十、从离屏创建 Fiber
export function createFiberFromOffscreen(
pendingProps: OffscreenProps,
mode: TypeOfMode,
lanes: Lanes,
key: ReactKey,
): Fiber {
const fiber = createFiber(OffscreenComponent, pendingProps, key, mode);
fiber.lanes = lanes;
return fiber;
}
十一、从活动创建 Fiber
export function createFiberFromActivity(
pendingProps: ActivityProps,
mode: TypeOfMode,
lanes: Lanes,
key: ReactKey,
): Fiber {
const fiber = createFiber(ActivityComponent, pendingProps, key, mode);
fiber.elementType = REACT_ACTIVITY_TYPE;
fiber.lanes = lanes;
return fiber;
}
十二、从视图过渡创建 Fiber
export function createFiberFromViewTransition(
pendingProps: ViewTransitionProps,
mode: TypeOfMode,
lanes: Lanes,
key: ReactKey,
): Fiber {
if (!enableSuspenseyImages) {
// Render a ViewTransition component opts into SuspenseyImages mode even
// when the flag is off.
// 即使标志关闭,渲染 ViewTransition 组件也会选择 SuspenseyImages 模式。
mode |= SuspenseyImagesMode;
}
const fiber = createFiber(ViewTransitionComponent, pendingProps, key, mode);
fiber.elementType = REACT_VIEW_TRANSITION_TYPE;
fiber.lanes = lanes;
const instance: ViewTransitionState = {
autoName: null,
paired: null,
clones: null,
ref: null,
};
fiber.stateNode = instance;
return fiber;
}
十三、从传统隐藏创建 Fiber
export function createFiberFromLegacyHidden(
pendingProps: LegacyHiddenProps,
mode: TypeOfMode,
lanes: Lanes,
key: ReactKey,
): Fiber {
const fiber = createFiber(LegacyHiddenComponent, pendingProps, key, mode);
fiber.elementType = REACT_LEGACY_HIDDEN_TYPE;
fiber.lanes = lanes;
return fiber;
}
十四、从跟踪标记创建Fiber
export function createFiberFromTracingMarker(
pendingProps: any,
mode: TypeOfMode,
lanes: Lanes,
key: ReactKey,
): Fiber {
const fiber = createFiber(TracingMarkerComponent, pendingProps, key, mode);
fiber.elementType = REACT_TRACING_MARKER_TYPE;
fiber.lanes = lanes;
const tracingMarkerInstance: TracingMarkerInstance = {
tag: TransitionTracingMarker,
transitions: null,
pendingBoundaries: null,
aborts: null,
name: pendingProps.name,
};
fiber.stateNode = tracingMarkerInstance;
return fiber;
}
十五、从文本创建 Fiber
export function createFiberFromText(
content: string,
mode: TypeOfMode,
lanes: Lanes,
): Fiber {
const fiber = createFiber(HostText, content, null, mode);
fiber.lanes = lanes;
return fiber;
}
十六、从脱水片段创建 Fiber
export function createFiberFromDehydratedFragment(
dehydratedNode: SuspenseInstance | ActivityInstance,
): Fiber {
const fiber = createFiber(DehydratedFragment, null, null, NoMode);
fiber.stateNode = dehydratedNode;
return fiber;
}
十七、从门户创建 Fiber
export function createFiberFromPortal(
portal: ReactPortal,
mode: TypeOfMode,
lanes: Lanes,
): Fiber {
const pendingProps = portal.children !== null ? portal.children : [];
const fiber = createFiber(HostPortal, pendingProps, portal.key, mode);
fiber.lanes = lanes;
fiber.stateNode = {
containerInfo: portal.containerInfo,
// 用于持久更新
pendingChildren: null, // Used by persistent updates
implementation: portal.implementation,
};
return fiber;
}
十八、从抛出创建 Fiber
备注
()由 [] 实现()由 [] 提供()由宿主环境提供
export function createFiberFromThrow(
error: mixed,
mode: TypeOfMode,
lanes: Lanes,
): Fiber {
const fiber = createFiber(Throw, error, null, mode);
fiber.lanes = lanes;
return fiber;
}
十九、常数
1. 创建 Fiber
const createFiber = enableObjectFiber
? createFiberImplObject
: createFiberImplClass;
二十、变量
1. 有坏的 Map 填充
信息
在 [ES 14 (ECMAScript 2023 )] 之前,WeakMap 的键只能是「可扩展对象」(即未被 Object.freeze() 、 Object.seal() 处理的对象),否则会抛出 TypeError
let hasBadMapPolyfill;
if (__DEV__) {
hasBadMapPolyfill = false;
try {
const nonExtensibleObject = Object.preventExtensions({});
new Map([[nonExtensibleObject, null]]);
new Set([nonExtensibleObject]);
} catch (e) {
// TODO: Consider warning about bad polyfills
// 待办:考虑提醒有问题的填充功能
hasBadMapPolyfill = true;
}
}
廿一、工具
1. Fiber 节点
信息
enableObjectFiber: 将 Fiber 的创建切换为使用简单对象而不是构造函数。
实际上 Fiber 的构建有两种方式,可通过特定平台设定 enableObjectFiber 值来切换。或者是开发者想看一看(水代码)哪个实现方式更好
function FiberNode(
this: $FlowFixMe,
tag: WorkTag,
pendingProps: mixed,
key: ReactKey,
mode: TypeOfMode,
) {
// Instance
// 实例
this.tag = tag;
this.key = key;
this.elementType = null;
this.type = null;
this.stateNode = null;
// Fiber
// Fiber (下面这几个属性的类型为 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;
if (enableProfilerTimer) {
// Note: The following is done to avoid a v8 performance cliff.
// 注意:以下操作是为了避免 v8 性能下降。
//
// Initializing the fields below to smis and later updating them with
// double values will cause Fibers to end up having separate shapes.
// This behavior/bug has something to do with Object.preventExtension().
// Fortunately this only impacts DEV builds.
// Unfortunately it makes React unusably slow for some applications.
// To work around this, initialize the fields below with doubles.
//
// 将下面的字段初始化为smis,然后再用双精度值更新它们,会导致Fibers最终具有不同的形状。
// 这种行为/错误与Object.preventExtension()有关。
// 幸运的是,这只影响开发版本。
// 不幸的是,这会使某些应用中的React变得非常慢。
// 为了解决这个问题,请用双精度值初始化下面的字段。
//
// Learn more about this here:
// https://github.com/facebook/react/issues/14365
// https://bugs.chromium.org/p/v8/issues/detail?id=8538
this.actualDuration = -0;
this.actualStartTime = -1.1;
this.selfBaseDuration = -0;
this.treeBaseDuration = -0;
}
if (__DEV__) {
// This isn't directly used but is handy for debugging internals:
// 这不是直接使用的,但对于调试内部功能很有用:
this._debugInfo = null;
this._debugOwner = null;
this._debugStack = null;
this._debugTask = null;
this._debugNeedsRemount = false;
this._debugHookTypes = null;
if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
Object.preventExtensions(this);
}
}
}
2. 创建 Fiber 实现类
// This is a constructor function, rather than a POJO constructor, still
// please ensure we do the following:
// 1) Nobody should add any instance methods on this. Instance methods can be
// more difficult to predict when they get optimized and they are almost
// never inlined properly in static compilers.
// 2) Nobody should rely on `instanceof Fiber` for type testing. We should
// always know when it is a fiber.
// 3) We might want to experiment with using numeric keys since they are easier
// to optimize in a non-JIT environment.
// 4) We can easily go from a constructor to a createFiber object literal if that
// is faster.
// 5) It should be easy to port this to a C struct and keep a C implementation
// compatible.
//
// 这是一个构造函数,而不是普通的 POJO 构造函数,仍然
// 请确保我们做到以下几点:
// 1)不要有人在此添加任何实例方法。实例方法在优化时可能更难预测,
// 并且在静态编译器中几乎从不正确内联。
// 2)不要有人依赖 `instanceof Fiber` 进行类型测试。我们应该
// 总是知道何时它是 fiber。
// 3)我们可能想尝试使用数字键,因为它们在非 JIT 环境中更容易优化。
// 4)如果这样更快,我们可以轻松地从构造函数转换为 createFiber 对象字面量。
// 5)将其移植到 C 结构并保持与 C 实现兼容应该很容易。
function createFiberImplClass(
tag: WorkTag,
pendingProps: mixed,
key: ReactKey,
mode: TypeOfMode,
): Fiber {
return new FiberNode(tag, pendingProps, key, mode);
}
3. 创建 Fiber 实现对象
// 创建 Fiber 实现对象
function createFiberImplObject(
tag: WorkTag,
pendingProps: mixed,
key: ReactKey,
mode: TypeOfMode,
): Fiber {
const fiber: Fiber = {
// Instance
// 实例
// tag, key - defined at the bottom as dynamic properties
// 标签,键 - 在底部作为动态属性定义
elementType: null,
type: null,
stateNode: null,
// Fiber
// Fiber
return: null,
child: null,
sibling: null,
index: 0,
ref: null,
refCleanup: null,
// pendingProps - defined at the bottom as dynamic properties
// pendingProps - 在底部定义为动态属性
memoizedProps: null,
updateQueue: null,
memoizedState: null,
dependencies: null,
// Effects
// 影响(副作用们)
flags: NoFlags,
subtreeFlags: NoFlags,
deletions: null,
lanes: NoLanes,
childLanes: NoLanes,
alternate: null,
// dynamic properties at the end for more efficient hermes bytecode
// 在末尾使用动态属性以提高 Hermes 字节码的效率
tag,
key,
pendingProps,
mode,
};
if (enableProfilerTimer) {
fiber.actualDuration = -0; // 实际持续时间
fiber.actualStartTime = -1.1; // 实际开始时间
fiber.selfBaseDuration = -0; // 自身基础持续时间
fiber.treeBaseDuration = -0; // 树基础持续时间
}
if (__DEV__) {
// This isn't directly used but is handy for debugging internals:
// 这不是直接使用的,但对于调试内部功能很方便:
fiber._debugInfo = null;
fiber._debugOwner = null;
fiber._debugStack = null;
fiber._debugTask = null;
fiber._debugNeedsRemount = false;
fiber._debugHookTypes = null;
if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
Object.preventExtensions(fiber);
}
}
return fiber;
}
4. 应该构建
function shouldConstruct(Component: Function) {
const prototype = Component.prototype;
return !!(prototype && prototype.isReactComponent);
}
5. 从范围创建 Fiber
function createFiberFromScope(
scope: ReactScope,
pendingProps: any,
mode: TypeOfMode,
lanes: Lanes,
key: null | string,
) {
const fiber = createFiber(ScopeComponent, pendingProps, key, mode);
fiber.type = scope;
fiber.elementType = scope;
fiber.lanes = lanes;
return fiber;
}
6. 从分析器创建 Fiber
function createFiberFromProfiler(
pendingProps: any,
mode: TypeOfMode,
lanes: Lanes,
key: null | string,
): Fiber {
if (__DEV__) {
if (typeof pendingProps.id !== 'string') {
console.error(
'Profiler must specify an "id" of type `string` as a prop. Received the type `%s` instead.',
typeof pendingProps.id,
);
}
}
const fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode);
fiber.elementType = REACT_PROFILER_TYPE;
fiber.lanes = lanes;
if (enableProfilerTimer) {
fiber.stateNode = {
effectDuration: 0,
passiveEffectDuration: 0,
};
}
return fiber;
}