在 React 内部实现中,将 render 函数分为两个阶段:
- 渲染阶段
- 提交阶段
其中渲染阶段可以分为 beginWork 和 completeWork 两个阶段,而提交阶段对应着 commitWork。
在之前的root.render过程中,渲染过程无论是并发模式执行还是同步模式执行,都是执行到函数performUnitOfWork,所以,这次,具体看看performUnitOfWork函数的执行过程。

workLoopSync

performUnitOfWork
performUnitOfWork
函数的主要作用是执行单个 Fiber
节点的工作单元。该函数会根据当前 Fiber
节点的状态,调用 beginWork
函数开始处理这个 Fiber
节点,并根据处理结果决定是继续处理下一个 Fiber
节点,还是完成当前 Fiber
节点的工作。
函数参数含义
- unitOfWork:类型为
Fiber
,表示当前要处理的Fiber
节点,也就是当前的工作单元。
javascript
function performUnitOfWork(unitOfWork: Fiber): void {
// unitOfWork.alternate 指向当前 Fiber 节点的替代节点。在 React 的协调过程中,每个 Fiber 节点都有一个对应的替代节点,用于在双缓冲机制中存储旧的状态。这里将其赋值给 current。
const current = unitOfWork.alternate;
// next:用于存储 beginWork 函数返回的下一个要处理的 Fiber 节点。
let next;
// 调用 beginWork 函数开始处理当前 Fiber 节点,传入当前 Fiber 节点的替代节点 current、当前 Fiber 节点 unitOfWork 以及相关的渲染车道 entangledRenderLanes。beginWork 函数会根据 Fiber 节点的类型和状态,执行相应的工作,如创建新的 Fiber 节点、更新已有 Fiber 节点等,并返回下一个要处理的 Fiber 节点。
next = beginWork(current, unitOfWork, entangledRenderLanes);
// 将 unitOfWork 的 pendingProps(待处理的属性)赋值给 memoizedProps(记忆化的属性)。这意味着当前 Fiber 节点的属性已经被处理并确定下来。
unitOfWork.memoizedProps = unitOfWork.pendingProps;
// 如果 next 为 null,说明 beginWork 函数没有返回下一个要处理的 Fiber 节点,即当前 Fiber 节点的工作没有产生新的工作。
if (next === null) {
// If this doesn't spawn new work, complete the current work.
// 调用 completeUnitOfWork 函数完成当前 Fiber 节点的工作,可能会进行一些清理和提交操作。
completeUnitOfWork(unitOfWork);
} else {
// 如果 next 不为 null,将 next 赋值给 workInProgress,表示下一个要处理的 Fiber 节点成为当前的工作进行中的节点,后续将继续处理这个节点。
workInProgress = next;
}
}
渲染阶段一beginWork
beginWork
函数的主要任务是根据不同的 Fiber
节点类型和更新情况,对当前 Fiber
节点进行处理,决定是复用旧的 Fiber
节点,还是创建新的子 Fiber
节点。该函数会根据 Fiber
节点的 tag
属性(表示节点类型),调用不同的处理函数来更新或挂载节点。
beginWork
函数接收三个参数:
current
:旧的 Fiber 节点,若为null
则表示没有旧节点。workInProgress
:新的 Fiber 节点,也就是要进行处理的节点。renderLanes
:渲染优先级车道,用于标识当前渲染任务的优先级。
javascript
function beginWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
): Fiber | null {
// 有旧节点,非首次渲染
if (current !== null) {
// current.memoizedProps 存储了旧 Fiber 节点上一次渲染时使用的属性。
const oldProps = current.memoizedProps;
// workInProgress.pendingProps 存储了新 Fiber 节点即将使用的属性。
const newProps = workInProgress.pendingProps;
if (
oldProps !== newProps ||
hasLegacyContextChanged() )
) {
didReceiveUpdate = true;
} else {
const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(
current,
renderLanes,
);
// 尝试提前退出渲染流程
if (
!hasScheduledUpdateOrContext &&
(workInProgress.flags & DidCapture) === NoFlags
) {
// No pending updates or context. Bail out now.
didReceiveUpdate = false;
return attemptEarlyBailoutIfNoScheduledUpdate(
current,
workInProgress,
renderLanes,
);
}
if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {
didReceiveUpdate = true;
} else {
didReceiveUpdate = false;
}
}
} else {
// 首次渲染时,将 didReceiveUpdate 标记为 false。
didReceiveUpdate = false;
}
// 将 workInProgress.lanes 设置为 NoLanes 时,意味着当前 Fiber 节点没有需要处理的更新任务,或者更新任务已经处理完毕。
// 会清除当前 workInProgress Fiber 节点上的所有更新标记。
workInProgress.lanes = NoLanes;
switch (workInProgress.tag) {
// 省略代码。。。
case Throw: {
// This represents a Component that threw in the reconciliation phase.
// So we'll rethrow here. This might be a Thenable.
throw workInProgress.pendingProps;
}
}
}
<Tag>FunctionComponent(常量为0)
负责解析函数组件的 props,并调用 updateFunctionComponent
执行组件的实际渲染。主要工作包括:
- 获取组件类型和待处理的 props。
- 解析默认 props(针对非类组件)。
- 调用函数组件的更新逻辑。
javascript
case FunctionComponent: {
// fiber的组件类型
const Component = workInProgress.type;
// 待处理props
const unresolvedProps = workInProgress.pendingProps;
const resolvedProps =
disableDefaultPropsExceptForClasses ||
workInProgress.elementType === Component
? unresolvedProps
: resolveDefaultPropsOnNonClassComponent(Component, unresolvedProps);
return updateFunctionComponent(
current,// 表示当前的 Fiber 节点
workInProgress,// 正在处理的fiber
Component,// 函数组件
resolvedProps,// 解析后的属性props
renderLanes,// 渲染优先级车道
);
}
updateFunctionComponent
updateFunctionComponent
函数负责执行函数组件,处理 Hooks,并根据返回的 JSX 内容生成新的子 Fiber 节点。该函数实现了函数组件的渲染逻辑、状态管理以及性能优化(如 bailout 机制)。
javascript
function updateFunctionComponent(
current: null | Fiber,
workInProgress: Fiber,
Component: any,
nextProps: any,
renderLanes: Lanes,
) {
let context;
if (!disableLegacyContext && !disableLegacyContextForFunctionComponents) {
// // 未屏蔽的上下文
const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);
// 经过屏蔽的上下文
context = getMaskedContext(workInProgress, unmaskedContext);
}
let nextChildren;
let hasId;
prepareToReadContext(workInProgress, renderLanes);
// 执行hooks
nextChildren = renderWithHooks(
current,
workInProgress,
Component,
nextProps,
context,
renderLanes,
);
// 表示组件没有接收到新的更新。
if (current !== null && !didReceiveUpdate) {
// bailoutHooks 会跳过 Hooks 的更新
bailoutHooks(current, workInProgress, renderLanes);
// 直接复用之前的结果。
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
// React DevTools reads this flag.
// 标记已完成
workInProgress.flags |= PerformedWork;
//reconcileChildren 函数用于对比新旧子节点,生成新的 Fiber 树结构。
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
工具函数之 resolveDefaultPropsOnNonClassComponent
resolveDefaultPropsOnNonClassComponent
是 React 中用于处理非类组件(如函数组件)默认 props 的函数。它会将组件定义的 defaultProps
对象与实际传入的 props 合并,确保未显式提供的 props 使用默认值。
函数参数含义:
Component
:组件本身(函数或类)。baseProps
:实际传入的 props 对象。
javascript
function resolveDefaultPropsOnNonClassComponent(
Component: any,
baseProps: Object,
): Object {
// 若启用则仅对类组件保留默认 props 支持,函数组件将完全忽略 defaultProps。
if (disableDefaultPropsExceptForClasses) {
// Support for defaultProps is removed in React 19 for all types
// except classes.
return baseProps;
}
// 合并默认 props
if (Component && Component.defaultProps) {
// Resolve default props. Taken from ReactElement
const props = assign({}, baseProps);
const defaultProps = Component.defaultProps;
for (const propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
return props;
}
return baseProps;
}
工具函数之 bailoutHooks
bailoutHooks
函数用于在组件无需重新渲染时跳过 Hooks 的更新。当组件的 props、context 或状态没有变化时,React 会触发 bailout 逻辑,直接复用之前的渲染结果,从而避免不必要的计算和副作用执行。
TypeScript
function bailoutHooks(
current: Fiber,
workInProgress: Fiber,
lanes: Lanes,
): void {
// 复用 Hooks 更新队列
workInProgress.updateQueue = current.updateQueue;
// 清除副作用
// PassiveEffect:表示存在需要异步执行的副作用(如 useEffect)。
// UpdateEffect:表示存在需要同步执行的副作用(如 useLayoutEffect)。
workInProgress.flags &= ~(PassiveEffect | UpdateEffect);
// 从当前 Fiber 的 lanes 中移除本次渲染的优先级,表示该优先级的更新已处理完毕。
current.lanes = removeLanes(current.lanes, lanes);
}
bailout 机制通常在以下情况触发:
- props 未变化 :前后 props 对象通过浅比较(
Object.is
)相等。 - context 未变化:组件依赖的上下文值没有更新。
- 被 React.memo 包裹 :函数组件被
React.memo
高阶组件包裹,且 props 未变化。 - 无状态更新:组件内部状态没有变化。
工具函数之 bailoutOnAlreadyFinishedWork
bailoutOnAlreadyFinishedWork
函数用于在组件无需重新渲染时直接复用现有 Fiber 树结构。当组件的 props、状态或上下文没有变化时,React 会触发 bailout 逻辑,跳过该组件及其子树的协调过程,直接复用之前的渲染结果,从而显著提升性能。
TypeScript
function bailoutOnAlreadyFinishedWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
): Fiber | null {
if (current !== null) {
// 直接将当前 Fiber 的依赖信息复制到新 Fiber,避免重新收集依赖。
workInProgress.dependencies = current.dependencies;
}
// 标记跳过的更新优先级
markSkippedUpdateLanes(workInProgress.lanes);
// Check if the children have any pending work.
if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {
// 启用延迟上下文传播的
if (enableLazyContextPropagation && current !== null) {
lazilyPropagateParentContextChanges(current, workInProgress, renderLanes);
if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {
return null;
}
} else {
return null;
}
}
// 克隆子节点
cloneChildFibers(current, workInProgress);
return workInProgress.child;
}
工具函数之 markSkippedUpdateLanes
markSkippedUpdateLanes
是 React 性能监控系统中的关键函数,用于记录被跳过的更新优先级。当组件由于 bailout 机制(如 props 未变化)而跳过渲染时,React 使用该函数标记这些被跳过的优先级
javascript
function markSkippedUpdateLanes(lane: Lane | Lanes): void {
workInProgressRootSkippedLanes = mergeLanes(
lane,
workInProgressRootSkippedLanes,
);
}
let workInProgressRootSkippedLanes: Lanes = NoLanes;
工具函数之 includesSomeLane
includesSomeLane
函数用于判断两个优先级集合(Lanes
)是否存在交集。
TypeScript
function includesSomeLane(a: Lanes | Lane, b: Lanes | Lane): boolean {
return (a & b) !== NoLanes;
}
工具函数之 cloneChildFibers
cloneChildFibers
函数用于在组件 bailout(跳过渲染)时浅克隆子 Fiber 节点。当父组件因 props 未变化而无需重新渲染时,React 会复用子 Fiber 结构,通过克隆操作创建新的 workInProgress 树,避免重新协调整个子树,从而显著提升性能。
javascript
function cloneChildFibers(
current: Fiber | null,
workInProgress: Fiber,
): void {
// 若 current 存在且子节点已变化,抛出错误
if (current !== null && workInProgress.child !== current.child) {
throw new Error('Resuming work not yet implemented.');
}
if (workInProgress.child === null) {
return;
}
// 克隆首个子节点
let currentChild = workInProgress.child;
let newChild = createWorkInProgress(currentChild, currentChild.pendingProps);
workInProgress.child = newChild;
newChild.return = workInProgress;
// 循环克隆所有兄弟节点
while (currentChild.sibling !== null) {
currentChild = currentChild.sibling;
newChild = newChild.sibling = createWorkInProgress(
currentChild,
currentChild.pendingProps,
);
newChild.return = workInProgress;
}
// 最后一个节点的 sibling 设为 null,确保链表正确结束。
newChild.sibling = null;
}
工具函数之 prepareToReadContext
prepareToReadContext
函数是 React 渲染流程中的关键环节,用于为当前 Fiber 节点准备上下文读取环境。它主要完成以下工作:
- 设置当前渲染的 Fiber 节点。
- 重置上下文依赖链表。
- 处理上下文更新标记,确保依赖的上下文变化能触发组件重新渲染。
javascript
function prepareToReadContext(
workInProgress: Fiber,
renderLanes: Lanes,
): void {
// currentlyRenderingFiber:全局变量,指向当前正在渲染的 Fiber 节点。
// lastContextDependency:全局变量,用于构建上下文依赖链表,初始化为 null。
currentlyRenderingFiber = workInProgress;
lastContextDependency = null;
const dependencies = workInProgress.dependencies;
if (dependencies !== null) {
if (enableLazyContextPropagation) {
// Reset the work-in-progress list
// 重置依赖链表(延迟传播模式)
dependencies.firstContext = null;
} else {
const firstContext = dependencies.firstContext;
if (firstContext !== null) {
if (includesSomeLane(dependencies.lanes, renderLanes)) {
// Context list has a pending update. Mark that this fiber performed work.
// 上下文有更新,标记当前 Fiber 执行了工作
markWorkInProgressReceivedUpdate();
}
// Reset the work-in-progress list
dependencies.firstContext = null;
}
}
}
}
<Tag>HostRoot
javascript
case HostRoot:
return updateHostRoot(current, workInProgress, renderLanes);
工具函数之 updateHostRoot
updateHostRoot
是 React 渲染流程中处理根组件(HostRoot
Fiber)的核心函数,负责协调根组件的更新逻辑,包括状态处理、子节点 reconciliation、服务端渲染水合(Hydration)等。
javascript
function updateHostRoot(
current: null | Fiber,
workInProgress: Fiber,
renderLanes: Lanes,
) {
// 推入根组件的上下文,确保子组件能访问正确的根状态。
// pushHostRootContext(workInProgress);
if (current === null) {
throw new Error('Should have a current fiber. This is a bug in React.');
}
// 获取新 props 和旧状态
const nextProps = workInProgress.pendingProps;
const prevState = workInProgress.memoizedState;
const prevChildren = prevState.element;
// 复制当前更新队列到新的 workInProgress Fiber,确保更新操作的不可变性。
cloneUpdateQueue(current, workInProgress);
// 计算新的根状态(nextState),处理状态更新(如 setState)和副作用。
processUpdateQueue(workInProgress, nextProps, null, renderLanes);
const nextState: RootState = workInProgress.memoizedState;
const root: FiberRoot = workInProgress.stateNode;
// pushRootTransition(workInProgress, root, renderLanes);
// suspendIfUpdateReadFromEntangledAsyncAction();
const nextChildren = nextState.element;
if (supportsHydration && prevState.isDehydrated) {
} else {
// resetHydrationState();
// 若新子节点与旧子节点相同,通过 bailout 跳过调和过程,直接复用现有 Fiber。
if (nextChildren === prevChildren) {
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
// 当子节点变化时,通过 reconcileChildren 生成新的子 Fiber 树,进入 diff 流程。
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
}
return workInProgress.child;
}
工具函数之 cloneUpdateQueue
cloneUpdateQueue
是 React 内部用于克隆更新队列(Update Queue)的核心函数,主要作用是在调和(Reconciliation)阶段为 workInProgress
Fiber 创建当前 Fiber(current
)的更新队列副本。
javascript
function cloneUpdateQueue<State>(
current: Fiber,
workInProgress: Fiber,
): void {
// Clone the update queue from current. Unless it's already a clone.
const queue: UpdateQueue<State> = (workInProgress.updateQueue: any);
const currentQueue: UpdateQueue<State> = (current.updateQueue: any);
// 仅当新旧队列引用相同时才执行克隆(避免重复克隆)
if (queue === currentQueue) {
const clone: UpdateQueue<State> = {
baseState: currentQueue.baseState,
firstBaseUpdate: currentQueue.firstBaseUpdate,
lastBaseUpdate: currentQueue.lastBaseUpdate,
shared: currentQueue.shared,
callbacks: null, // 重置回调,避免旧回调影响新 Fiber
};
workInProgress.updateQueue = clone;
}
}
javascript
interface UpdateQueue<State> {
baseState: State; // 基础状态(未处理更新的状态)
firstBaseUpdate: Update<State>; // 第一个未处理的更新
lastBaseUpdate: Update<State>; // 最后一个未处理的更新
shared: { [key: string]: mixed }; // 共享状态(如上下文)
callbacks: Callback | null; // 更新回调函数
}
工具函数之 processUpdateQueue
processUpdateQueue函数的核心作用是将组件的状态更新队列(queue
)中的更新合并到当前状态(inst.state
),确保状态按顺序更新,并处理函数式更新和对象合并逻辑。
javascript
function processUpdateQueue(
internalInstance: InternalInstance,
inst: any,
props: any,
maskedLegacyContext: any,
): void {
if (internalInstance.queue !== null && internalInstance.queue.length > 0) {
// 处理更新队列
const oldQueue = internalInstance.queue;
// oldReplace:表示是否用新状态完全替换旧状态(而非合并)。
const oldReplace = internalInstance.replace;
// 重置队列为 null,避免重复处理
internalInstance.queue = null;
// 重置替换标志
internalInstance.replace = false;
// 仅一个更新项,直接替换状态。
if (oldReplace && oldQueue.length === 1) {
inst.state = oldQueue[0];
} else {
// 初始化 nextState
let nextState = oldReplace ? oldQueue[0] : inst.state;
// 是否需要创建新对象(避免直接修改旧状态)
let dontMutate = true;
// 遍历更新队列(从第一个有效更新开始)
for (let i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {
// 获取当前更新项
const partial = oldQueue[i];
const partialState =
typeof partial === 'function'
// 处理函数式更新(如 setState((state) => ({ ...state, count: state.count + 1 })))
? partial.call(inst, nextState, props, maskedLegacyContext)
// 非函数式更新直接使用值
: partial;
if (partialState != null) {
if (dontMutate) {
// 首次修改,创建新对象以保持不可变性
dontMutate = false;
nextState = assign({}, nextState, partialState);
} else {
// 后续修改直接合并(已创建新对象,可安全修改)
assign(nextState, partialState);
}
}
}
// 最终状态赋值
inst.state = nextState;
}
} else {
// 清空空队列
internalInstance.queue = null;
}
}
<Tag>HostHoistable
React 渲染流程中处理 可提升资源节点(HostHoistable) 。当浏览器支持资源优化(supportsResources
为 true
)时,会调用 updateHostHoistable
函数对这类节点进行特殊处理,以优化关键资源(如 CSS、JavaScript)的加载顺序和优先级,从而提升应用性能。
javascript
case HostHoistable:
if (supportsResources) {
return updateHostHoistable(current, workInProgress, renderLanes);
}
updateHostHoistable
updateHostHoistable
是 React 渲染流程中处理 可提升资源节点(如 CSS、JS 等) 的核心函数。
优化关键资源的加载执行流程:
- 标记 ref 相关副作用
- 初始化或更新资源对象(通过
getResource
) - 管理资源状态(存储在
memoizedState
中) - 决定是否创建 DOM 实例(非资源节点或非水合模式下)
javascript
function updateHostHoistable(
current: null | Fiber,
workInProgress: Fiber,
renderLanes: Lanes,
) {
// 标记出来ref相关副作用
markRef(current, workInProgress);
// 首次渲染
if (current === null) {
// 通过 getResource 获取资源对象(如 CSS、JS 资源)
const resource = getResource(
workInProgress.type,
null,
workInProgress.pendingProps,
null,
);
if (resource) {
// 将资源对象存储在 memoizedState 中
workInProgress.memoizedState = resource;
} else {
if (!getIsHydrating()) {
// This is not a Resource Hoistable and we aren't hydrating so we construct the instance.
// 创建非资源类型的可提升节点(如普通 DOM 元素)
workInProgress.stateNode = createHoistableInstance(
workInProgress.type,
workInProgress.pendingProps,
getRootHostContainer(),
workInProgress,
);
}
}
} else {
// Get Resource may or may not return a resource. either way we stash the result
// on memoized state.
// 对比新旧 props,决定是否需要更新资源
// 复用或创建新资源对象,更新到 memoizedState
workInProgress.memoizedState = getResource(
workInProgress.type,
current.memoizedProps,
workInProgress.pendingProps,
current.memoizedState,
);
}
return null;
}
工具函数之 markRef
markRef
函数主要作用是标记 workInProgress
Fiber 是否需要执行 ref
相关的副作用(Effect)。
javascript
function markRef(current: Fiber | null, workInProgress: Fiber) {
const ref = workInProgress.ref;
if (ref === null) {
if (current !== null && current.ref !== null) {
// Schedule a Ref effect
workInProgress.flags |= Ref | RefStatic;
}
} else {
if (typeof ref !== 'function' && typeof ref !== 'object') {
throw new Error(
'Expected ref to be a function, an object returned by React.createRef(), or undefined/null.',
);
}
if (current === null || current.ref !== ref) {
// Schedule a Ref effect
workInProgress.flags |= Ref | RefStatic;
}
}
}
createHoistableInstance
创建可提升实例
javascript
function createHoistableInstance(
type: string,
props: Props,
rootContainerInstance: Container,
internalInstanceHandle: Object,
): Instance {
//n获取document对象
const ownerDocument = getOwnerDocumentFromRootContainer(
rootContainerInstance,
);
// 创建element
const domElement: Instance = ownerDocument.createElement(type);
// 用于建立 DOM 节点与 Fiber 节点双向映射
precacheFiberNode(internalInstanceHandle, domElement);
// 将 JSX 中的 props 信息存储到对应 DOM 节点上
updateFiberProps(domElement, props);
setInitialProperties(domElement, type, props);
// 标记 DOM 节点为 可提升(Hoistable)
markNodeAsHoistable(domElement);
return domElement;
}
工具函数之 precacheFiberNode
precacheFiberNode
是 React 内部用于建立 DOM 节点与 Fiber 节点双向映射的核心函数。
javascript
function precacheFiberNode(
hostInst: Fiber,
node: Instance | TextInstance | SuspenseInstance | ReactScopeInstance,
): void {
(node: any)[internalInstanceKey] = hostInst;
}
const internalInstanceKey = '__reactFiber$' + randomKey;
工具函数之 updateFiberProps
updateFiberProps
是 React 内部用于将 JSX 中的 props 信息存储到对应 DOM 节点上的工具函数。
javascript
function updateFiberProps(
node: Instance | TextInstance | SuspenseInstance,
props: Props,
): void {
(node: any)[internalPropsKey] = props;
}
const internalPropsKey = '__reactProps$' + randomKey;
工具函数之 markNodeAsHoistable
markNodeAsHoistable
是 React 内部用于标记 DOM 节点为 可提升(Hoistable) 的工具函数。
javascript
function markNodeAsHoistable(node: Node) {
(node: any)[internalHoistableMarker] = true;
}
const internalHoistableMarker = '__reactMarker$' + randomKey;
getResource
getResource
是 React 内部用于管理和复用关键资源(如 CSS、JavaScript 文件)的核心函数。它通过资源根节点(resourceRoot
)追踪已加载的资源,实现资源共享、预加载和避免重复加载,从而优化应用性能。
javascript
function getResource(
type: string,
currentProps: any,
pendingProps: any,
currentResource: null | Resource,
): null | Resource {
// 获取资源根节点
const resourceRoot = getCurrentResourceRoot();
if (!resourceRoot) {
throw new Error(
'"resourceRoot" was expected to exist. This is a bug in React.',
);
}
switch (type) {
case 'meta':
case 'title': {
return null;
}
// 处理资源类型style
case 'style': {
if (
// precedence:样式优先级(如 'high'、'low'),用于控制加载顺序。
typeof pendingProps.precedence === 'string' &&
// href:外部样式表的 URL。
typeof pendingProps.href === 'string'
) {
// 资源键生成。getStyleKey:生成 URL 的唯一哈希值,确保相同 URL 的资源被复用。
const key = getStyleKey(pendingProps.href);
// 查找资源。hoistableStyles:Map 对象,键为资源 URL 哈希值,值为资源对象。
const styles = getResourcesFromRoot(resourceRoot).hoistableStyles;
let resource = styles.get(key);
if (!resource) {
// 资源对象结构
resource = {
type: 'style', // 资源类型
instance: null, // DOM 实例(加载后填充)
count: 0, // 引用计数(用于垃圾回收)
state: null, // 资源状态(如加载中、已完成)
};
// 将新资源存入缓存
styles.set(key, resource);
}
return resource;
}
// 无效资源处理
return {
type: 'void', // 特殊类型,表示无效资源
instance: null,
count: 0,
state: null,
};
}
// 处理资源类型link
case 'link': {
if (
// rel="stylesheet":确认是样式表资源
pendingProps.rel === 'stylesheet' &&
// href 和 precedence 存在且类型正确
typeof pendingProps.href === 'string' &&
typeof pendingProps.precedence === 'string'
) {
const qualifiedProps: StylesheetQualifyingProps = pendingProps;
// 生成唯一key
const key = getStyleKey(qualifiedProps.href);
// 查找资源
const styles = getResourcesFromRoot(resourceRoot).hoistableStyles;
let resource = styles.get(key);
if (!resource) {
const ownerDocument = getDocumentFromRoot(resourceRoot);
// 定义资源结构
resource = ({
type: 'stylesheet',
instance: null, // 对应 DOM 元素
count: 0, // 引用计数
state: {
loading: NotLoaded, // 加载状态
preload: null, // 预加载 Promise
},
}: StylesheetResource);
// 存入缓存
styles.set(key, resource);
// 通过 CSS 选择器查找已存在的 <link> 标签
const instance = ownerDocument.querySelector(
getStylesheetSelectorFromKey(key),
);
if (instance) {
// 使用内部属性 _p 判断加载状态
const loadingState: ?Promise<mixed> = (instance: any)._p;
if (loadingState) {
// This instance is inserted as part of a boundary reveal and is not yet
// loaded
// 正在加载中
} else {
// 实例已经加载完成
// This instance is already loaded
resource.instance = instance;
resource.state.loading = Loaded | Inserted;
}
}
// 预加载机制流程:
// 生成预加载配置(如 as="style")
// 创建 <link rel="preload"> 标签
// 监听加载完成事件,更新资源状态
if (!preloadPropsMap.has(key)) {
const preloadProps = preloadPropsFromStylesheet(qualifiedProps);
preloadPropsMap.set(key, preloadProps);
if (!instance) {
preloadStylesheet(
ownerDocument,
key,
preloadProps,
resource.state,
);
}
}
}
// if (currentProps && currentResource === null) {
// let diff = '';
// }
return resource;
} else {
// if (currentProps && currentResource !== null) {
// let diff = '';
// }
return null;
}
}
case 'script': {
const async = pendingProps.async;
const src = pendingProps.src;
if (
typeof src === 'string' &&
async &&
typeof async !== 'function' &&
typeof async !== 'symbol'
) {
const key = getScriptKey(src);
const scripts = getResourcesFromRoot(resourceRoot).hoistableScripts;
let resource = scripts.get(key);
if (!resource) {
resource = {
type: 'script',
instance: null,
count: 0,
state: null,
};
scripts.set(key, resource);
}
return resource;
}
return {
type: 'void',
instance: null,
count: 0,
state: null,
};
}
default: {
throw new Error(
`getResource encountered a type it did not expect: "${type}". this is a bug in React.`,
);
}
}
}
1、处理style类型的资源
处理 外部样式表资源( **<style>**标签) 的逻辑分支。它通过 precedence
和 href
属性识别需要优化加载的样式资源,利用缓存机制避免重复加载,并返回标准化的资源对象。

2、处理link类型的资源
React 内部处理 <link rel="stylesheet">
资源的核心逻辑,主要负责:
- 资源去重:通过 URL 缓存避免重复加载同一 CSS 文件
- 状态管理:跟踪样式表的加载状态(未加载、加载中、已完成)
- 预加载优化 :使用
<link rel="preload">
加速关键样式的加载 - 服务端渲染集成:支持与 SSR 流程配合,提前收集关键 CSS

3、处理script类型的资源

工具函数之 preloadPropsFromStylesheet
preloadPropsFromStylesheet
是 React 内部用于将 <link rel="stylesheet">
转换为 <link rel="preload">
的工具函数。
javascript
function preloadPropsFromStylesheet(
props: StylesheetQualifyingProps,
): PreloadProps {
return {
rel: 'preload', // 将 rel 从 'stylesheet' 改为 'preload'
as: 'style', // 指定资源类型为样式表
href: props.href, // 保留原始 URL
crossOrigin: props.crossOrigin, // 跨域配置
integrity: props.integrity, // 内容完整性校验
media: props.media, // 媒体查询条件
hrefLang: props.hrefLang, // 语言设置
referrerPolicy: props.referrerPolicy, // 引用策略
};
}
html
// 原始 JSX
<link rel="stylesheet" href="critical.css" precedence="high" />
// React 处理后
<link rel="preload" as="style" href="critical.css" /> // 预加载阶段
<link rel="stylesheet" href="critical.css" /> // 正式应用阶段
工具函数之 preloadStylesheet
preloadStylesheet
是 React 内部用于预加载 CSS 资源的核心函数,通过创建 <link rel="preload">
标签实现样式表的并行加载,避免阻塞主线程渲染。
javascript
function preloadStylesheet(
ownerDocument: Document,
key: string,
preloadProps: PreloadProps,
state: StylesheetState,
) {
// 检查已有预加载标签
const preloadEl = ownerDocument.querySelector(
getPreloadStylesheetSelectorFromKey(key),
);
if (preloadEl) {
// If we find a preload already it was SSR'd and we won't have an actual
// loading state to track. For now we will just assume it is loaded
// 服务端渲染已插入预加载标签,直接标记为已加载
state.loading = Loaded;
} else {
// 创建预加载标签
const instance = ownerDocument.createElement('link');
state.preload = instance;
// 监听加载事件
instance.addEventListener('load', () => (state.loading |= Loaded));
instance.addEventListener('error', () => (state.loading |= Errored));
// 设置标签属性并插入文档
setInitialProperties(instance, 'link', preloadProps);
markNodeAsHoistable(instance); // 标记为可提升资源
(ownerDocument.head: any).appendChild(instance); // 插入到文档头部
}
}
javascript
function getPreloadStylesheetSelectorFromKey(key: string) {
return `link[rel="preload"][as="style"][${key}]`;
}
工具函数之 getCurrentResourceRoot
getCurrentResourceRoot()
是 React 内部用于获取当前渲染环境中 可提升资源根节点(HoistableRoot) 的工具函数。
javascript
function getCurrentResourceRoot(): null | HoistableRoot {
// 获取当前根容器
const currentContainer = getCurrentRootHostContainer();
// getHoistableRoot提取可提升资源根节点
return currentContainer ? getHoistableRoot(currentContainer) : null;
}
javascript
function getCurrentRootHostContainer(): null | Container {
return rootInstanceStackCursor.current;
}
javascript
function createCursor<T>(defaultValue: T): StackCursor<T> {
return {
current: defaultValue,
};
}
工具函数之 getHoistableRoot
javascript
function getHoistableRoot(container: Container): HoistableRoot {
return typeof container.getRootNode === 'function'
// Node 接口的 getRootNode() 方法返回上下文中的根节点
? container.getRootNode()
// Node.ownerDocument 只读属性会返回当前节点的顶层的 document 对象
: container.ownerDocument;
}
工具函数之 getResourcesFromRoot
javascript
function getResourcesFromRoot(root: HoistableRoot): RootResources {
// 获取节点上的设置的资源
let resources = (root: any)[internalRootNodeResourcesKey];
if (!resources) {
// 设置
resources = (root: any)[internalRootNodeResourcesKey] = {
hoistableStyles: new Map(),
hoistableScripts: new Map(),
};
}
return resources;
}
const internalRootNodeResourcesKey = '__reactResources$' + randomKey;
<Tag>HostSingleton
React 渲染流程中处理 单节点宿主组件。
javascript
// Fall through
case HostSingleton:
if (supportsSingletons) {
return updateHostSingleton(current, workInProgress, renderLanes);
}
updateHostSingleton
React 渲染流程中处理 宿主组件(如 HTML 标签)。 处理hook钩子函数。 执行过程: React 处理 处理 React 中 执行过程(启用资源管理): 一、初始化过程 二、更新过程 处理 React 中 React 处理 关键属性: 它执行以下核心操作: 处理过程: 一、突变模式 二、持久化模式 cloneHiddenInstance 方法,用于创建一个隐藏版本的 DOM 元素实例。该方法在需要临时隐藏元素但保留其结构和状态时使用。 它通过以下步骤实现精细控制: React 处理 获取根容器所属的 建立 Fiber 节点与 DOM 节点的映射 <Tag>HostPortal 处理 React 中 执行过程: 主要功能是为 React 应用的指定容器添加对所有支持的原生事件的监听。它会对事件监听进行去重处理,避免重复添加相同的事件监听器。同时,对于 React 渲染根节点(Root)的状态机,用于表示整个渲染过程中可能处于的不同阶段和结果。 React 内部用于标识不同类型组件和节点的常量(称为 标记节点状态和操作的位掩码常量(Flags)。每个标志都是一个二进制值,通过位运算可以高效地组合、检查和修改这些标志。updateHostSingleton
是 React 渲染流程中处理 单节点宿主组件(如
function updateHostSingleton(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
) {
// 将当前 Fiber 节点的上下文(如命名空间、文档模式)压入栈中
pushHostContext(workInProgress);
if (current === null) {
// 服务端渲染水合处理
// claimHydratableSingleton(workInProgress);
}
const nextChildren = workInProgress.pendingProps.children;
// 首次渲染
if (current === null && !getIsHydrating()) {
// 使用 reconcileChildFibers 创建新的子 Fiber 树
workInProgress.child = reconcileChildFibers(
workInProgress,
null,
nextChildren,
renderLanes,
);
} else {
// 更新
// 使用 reconcileChildren 对比新旧子节点,执行最小化 DOM 操作
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
}
// 标记ref副作用
markRef(current, workInProgress);
// 返回子 Fiber 节点
return workInProgress.child;
}
<Tag>HostComponent
// Fall through
case HostComponent:
return updateHostComponent(current, workInProgress, renderLanes);
工具函数之 updateHostComponent
updateHostComponent
是 React 渲染流程中处理 宿主组件(如 HTML 标签) 的核心函数。
function updateHostComponent(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
) {
if (current === null) {
// tryToClaimNextHydratableInstance(workInProgress);
}
// 设置当前渲染上下文
pushHostContext(workInProgress);
const type = workInProgress.type;
const nextProps = workInProgress.pendingProps;
const prevProps = current !== null ? current.memoizedProps : null;
let nextChildren = nextProps.children;
const isDirectTextChild = shouldSetTextContent(type, nextProps);
// 对于纯文本子节点(如 <div>Hello</div>),直接设置 textContent
// 避免创建额外的文本节点,提升渲染效率
if (isDirectTextChild) {
nextChildren = null;
} else if (prevProps !== null && shouldSetTextContent(type, prevProps)) {
// If we're switching from a direct text child to a normal child, or to
// empty, we need to schedule the text content to be reset.
workInProgress.flags |= ContentReset;
}
// 异步状态处理(并发模式)
if (enableAsyncActions) {
const memoizedState = workInProgress.memoizedState;
if (memoizedState !== null) {
// renderTransitionAwareHostComponentWithHooks 处理异步更新
const newState = renderTransitionAwareHostComponentWithHooks(
current,
workInProgress,
renderLanes,
);
// 根据渲染器类型(主渲染器或辅助渲染器)更新上下文值
if (isPrimaryRenderer) {
// _currentValue 存储主渲染器的上下文值
HostTransitionContext._currentValue = newState;
} else {
// _currentValue2 存储辅助渲染器的上下文值
HostTransitionContext._currentValue2 = newState;
}
// 懒传播
if (enableLazyContextPropagation) {
// In the lazy propagation implementation, we don't scan for matching
// consumers until something bails out.
} else {
if (didReceiveUpdate) {
if (current !== null) {
const oldStateHook: Hook = current.memoizedState;
const oldState: TransitionStatus = oldStateHook.memoizedState;
if (oldState !== newState) {
// 更新上下文并传播变化
propagateContextChange(
workInProgress,
HostTransitionContext,
renderLanes,
);
}
}
}
}
}
}
markRef(current, workInProgress);
// 协调子节点
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
renderTransitionAwareHostComponentWithHooks
function renderTransitionAwareHostComponentWithHooks(
current: Fiber | null,
workInProgress: Fiber,
lanes: Lanes,
): TransitionStatus {
if (!enableAsyncActions) {
throw new Error('Not implemented.');
}
return renderWithHooks(
current,
workInProgress,
TransitionAwareHostComponent,
null,
null,
lanes,
);
}
工具函数之 propagateContextChange
function propagateContextChange<T>(
workInProgress: Fiber,
context: ReactContext<T>,
renderLanes: Lanes,
): void {
if (enableLazyContextPropagation) {
const forcePropagateEntireTree = true;
propagateContextChanges(
workInProgress,
[context],
renderLanes,
forcePropagateEntireTree,
);
} else {
propagateContextChange_eager(workInProgress, context, renderLanes);
}
}
工具函数之 propagateContextChange_eager
propagateContextChange_eager
是 React 中用于 主动传播上下文变化 的核心函数(适用于非懒传播模式)。当上下文(Context
)的值发生改变时,该函数会遍历相关 Fiber 树,找到依赖该上下文的组件并为其标记更新,确保组件能响应上下文变化并重新渲染。
function propagateContextChange_eager<T>(
workInProgress: Fiber,
context: ReactContext<T>,
renderLanes: Lanes,
): void {
// Only used by eager implementation
if (enableLazyContextPropagation) {
return;
}
// Fiber 树遍历初始化
let fiber = workInProgress.child;
if (fiber !== null) {
// Set the return pointer of the child to the work-in-progress fiber.
// 设置子节点的 return 指针指向父节点
fiber.return = workInProgress;
}
// 深度优先遍历循环
while (fiber !== null) {
let nextFiber;
// Visit this fiber.
// 获取当前节点依赖的上下文列表
const list = fiber.dependencies;
if (list !== null) {
nextFiber = fiber.child;
let dependency = list.firstContext;
while (dependency !== null) {
// Check if the context matches.
// 匹配到目标上下文,触发更新逻辑
if (dependency.context === context) {
// Match! Schedule an update on this fiber.
// 为类组件生成强制更新
if (fiber.tag === ClassComponent) {
// Schedule a force update on the work-in-progress.
const lane = pickArbitraryLane(renderLanes);
const update = createUpdate(lane);
update.tag = ForceUpdate;
// Inlined `enqueueUpdate` to remove interleaved update check
// 入队更新(直接操作队列,避免中间检查)
const updateQueue = fiber.updateQueue;
if (updateQueue === null) {
// Only occurs if the fiber has been unmounted.
} else {
const sharedQueue: SharedQueue<any> = (updateQueue: any).shared;
const pending = sharedQueue.pending;
// update是是一个循环链表结构
if (pending === null) {
// This is the first update. Create a circular list.
update.next = update;
} else {
update.next = pending.next;
pending.next = update;
}
sharedQueue.pending = update;
}
}
// 标记当前节点及其 alternate 节点的更新优先级
fiber.lanes = mergeLanes(fiber.lanes, renderLanes);
const alternate = fiber.alternate;
if (alternate !== null) {
// 合并车道
alternate.lanes = mergeLanes(alternate.lanes, renderLanes);
}
// 向上传播任务到父路径
scheduleContextWorkOnParentPath(
fiber.return,
renderLanes,
workInProgress,
);
// Mark the updated lanes on the list, too.
list.lanes = mergeLanes(list.lanes, renderLanes);
// Since we already found a match, we can stop traversing the
// dependency list.
// 找到一个匹配后,无需继续遍历依赖列表
break;
}
dependency = dependency.next;
}
} else if (fiber.tag === ContextProvider) {
// Don't scan deeper if this is a matching provider
// 若当前节点是匹配的 Provider,停止向下遍历(避免重复处理)
nextFiber = fiber.type === workInProgress.type ? null : fiber.child;
} else if (fiber.tag === DehydratedFragment) {
// 处理 Suspense 边界的脱水片段,标记其父 Suspense 节点
const parentSuspense = fiber.return;
if (parentSuspense === null) {
throw new Error(
'We just came from a parent so we must have had a parent. This is a bug in React.',
);
}
parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes);
const alternate = parentSuspense.alternate;
if (alternate !== null) {
alternate.lanes = mergeLanes(alternate.lanes, renderLanes);
}
scheduleContextWorkOnParentPath(
parentSuspense,
renderLanes,
workInProgress,
);
// 跳过子树,直接处理兄弟节点
nextFiber = fiber.sibling;
} else {
// Traverse down.
nextFiber = fiber.child;
}
if (nextFiber !== null) {
// Set the return pointer of the child to the work-in-progress fiber.
nextFiber.return = fiber;
} else {
// No child. Traverse to next sibling.
nextFiber = fiber;
while (nextFiber !== null) {
if (nextFiber === workInProgress) {
// We're back to the root of this subtree. Exit.
nextFiber = null;
break;
}
const sibling = nextFiber.sibling;
if (sibling !== null) {
// Set the return pointer of the sibling to the work-in-progress fiber.
sibling.return = nextFiber.return;
nextFiber = sibling;
break;
}
// No more siblings. Traverse up.
nextFiber = nextFiber.return;
}
}
fiber = nextFiber;
}
}
工具函数之 scheduleContextWorkOnParentPath
scheduleContextWorkOnParentPath
是 React 中用于 向上传播上下文更新任务 的核心函数
function scheduleContextWorkOnParentPath(
parent: Fiber | null,
renderLanes: Lanes,
propagationRoot: Fiber,
) {
// Update the child lanes of all the ancestors, including the alternates.
let node = parent;
// 从当前父节点出发遍历
while (node !== null) {
// 获取备用 Fiber 节点(双缓冲机制)
const alternate = node.alternate;
// 检查当前节点的 childLanes 是否包含新的 renderLanes
if (!isSubsetOfLanes(node.childLanes, renderLanes)) {
// 合并车道
node.childLanes = mergeLanes(node.childLanes, renderLanes);
if (alternate !== null) {
// 同步更新备用节点
alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes);
}
} else if (
alternate !== null &&
!isSubsetOfLanes(alternate.childLanes, renderLanes)
) {
alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes);
}
// 到达传播根节点,停止遍历
if (node === propagationRoot) {
break;
}
// 向上处理父节点
node = node.return;
}
}
<Tag>HostText
case HostText:
return updateHostText(current, workInProgress);
updateHostText
function updateHostText(current: null | Fiber, workInProgress: Fiber) {
// 说明首次渲染或没有可对比的旧fiber
if (current === null) {
//tryToClaimNextHydratableTextInstance(workInProgress);
}
return null;
}
<Tag>HostPortal
case HostPortal:
return updatePortalComponent(current, workInProgress, renderLanes);
updatePortalComponent
function updatePortalComponent(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
) {
pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);
const nextChildren = workInProgress.pendingProps;
if (current === null) {
workInProgress.child = reconcileChildFibers(
workInProgress,
null,
nextChildren,
renderLanes,
);
} else {
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
}
return workInProgress.child;
}
渲染阶段二completeUnitOfWork
completeUnitOfWork
函数在 React 的协调过程中负责完成单个 Fiber
节点的工作单元。它会不断尝试完成当前 Fiber
节点的工作,处理可能出现的未完成情况,根据处理结果决定是继续处理兄弟节点还是返回父节点,直到完成整个 Fiber
树的工作,并在到达根节点时更新根节点的退出状态。
completedWork。
function completeUnitOfWork(unitOfWork: Fiber): void {
// completedWork 初始化为传入的 unitOfWork
let completedWork: Fiber = unitOfWork;
// 使用 do-while 循环来处理 Fiber 节点的工作
do {
// 检查 completedWork 的 flags 属性中是否包含 Incomplete 标志。如果包含,说明当前 Fiber 节点的工作未完成。
if ((completedWork.flags & Incomplete) !== NoFlags) {
const skipSiblings = workInProgressRootDidSkipSuspendedSiblings;
// 用 unwindUnitOfWork 函数处理未完成的工作
unwindUnitOfWork(completedWork, skipSiblings);
return;
}
// 获取当前 Fiber 节点的替代节点,用于存储旧的状态。
const current = completedWork.alternate;
// 获取当前 Fiber 节点的父节点,用于在完成当前节点工作后返回父节点继续处理。
const returnFiber = completedWork.return;
// 用于存储 completeWork 函数返回的下一个要处理的 Fiber 节点。
let next;
// 调用 startProfilerTimer 函数开始记录性能分析时间。
// startProfilerTimer(completedWork);
// 调用 completeWork 函数完成当前 Fiber 节点的工作,传入当前 Fiber 节点的替代节点 current、当前 Fiber 节点 completedWork 以及相关的渲染车道 entangledRenderLanes。
next = completeWork(current, completedWork, entangledRenderLanes);
// 如果 next 不为 null,说明完成当前 Fiber 节点的工作产生了新的工作。
if (next !== null) {
// Completing this fiber spawned new work. Work on that next.
// 将 next 赋值给 workInProgress,表示下一个要处理的 Fiber 节点成为当前的工作进行中的节点,函数直接返回。
workInProgress = next;
return;
}
// 获取当前 Fiber 节点的兄弟节点 siblingFiber。
const siblingFiber = completedWork.sibling;
if (siblingFiber !== null) {
// If there is more work to do in this returnFiber, do that next.
// 如果兄弟节点不为 null,将兄弟节点赋值给 workInProgress,表示接下来要处理兄弟节点的工作,函数直接返回。
workInProgress = siblingFiber;
return;
}
// 如果没有新产生的工作,也没有兄弟节点,将 completedWork 更新为其父节点 returnFiber,同时更新 workInProgress 为父节点,继续处理父节点的工作。
completedWork = returnFiber;
// Update the next thing we're working on in case something throws.
workInProgress = completedWork;
// 只要 completedWork 不为 null,就会继续循环处理。
} while (completedWork !== null);
// We've reached the root.
// 如果根节点的退出状态为 RootInProgress(正在进行中),将其更新为 RootCompleted(已完成)。
if (workInProgressRootExitStatus === RootInProgress) {
workInProgressRootExitStatus = RootCompleted;
}
}
completeWork
completeWork
函数的主要职责是根据当前 Fiber 节点的类型(通过 workInProgress.tag
标识),对该节点进行相应的处理,比如更新 DOM、设置属性等。(负责单个fiber节点的处理)
function completeWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
): Fiber | null {
const newProps = workInProgress.pendingProps;
popTreeContext(workInProgress);
switch (workInProgress.tag) {
// 省略的代码
case Throw: {
if (!disableLegacyMode) {
// Only Legacy Mode completes an errored node.
return null;
}
}
}
throw new Error(
`Unknown unit of work tag (${workInProgress.tag}). This error is likely caused by a bug in ` +
'React. Please file an issue.',
);
}
<Tag>FunctionComponent/LazyComponent/ForwardRef/...
case LazyComponent:
case SimpleMemoComponent:
case FunctionComponent:
case ForwardRef:
case Fragment:
case Mode:
case Profiler:
case ContextConsumer:
case MemoComponent:
bubbleProperties(workInProgress);
return null;
bubbleProperties
bubbleProperties
函数的主要功能是从一个已完成工作的 Fiber
节点(completedWork
)的子节点中收集信息,将这些信息冒泡到该节点上。这些信息主要包括子节点的渲染优先级车道(Lanes
)和副作用标志(Flags
)。
function bubbleProperties(completedWork: Fiber) {
// 如果 completedWork 存在替代节点(alternate),并且替代节点的子节点与当前节点的子节点相同,则认为可以跳过更新。
const didBailout =
completedWork.alternate !== null &&
completedWork.alternate.child === completedWork.child;
// 用于存储合并后的子节点的渲染优先级车道,初始化为 NoLanes(表示没有车道)。
let newChildLanes: Lanes = NoLanes;
// 用于存储合并后的子节点的副作用标志,初始化为 NoFlags(表示没有标志)。
let subtreeFlags = NoFlags;
// 未跳过更新的情况
if (!didBailout) {
let child = completedWork.child;
// 使用 while 循环遍历 completedWork 的所有子节点:
while (child !== null) {
// 合并子节点的 lanes 和 childLanes 到newChildLanes
newChildLanes = mergeLanes(
newChildLanes,
mergeLanes(child.lanes, child.childLanes),
);
// 将子节点的 subtreeFlags 和 flags 合并到 subtreeFlags 中
subtreeFlags |= child.subtreeFlags;
subtreeFlags |= child.flags;
child.return = completedWork;
// 继续下一个兄弟节点
child = child.sibling;
}
// 更新
completedWork.subtreeFlags |= subtreeFlags;
} else {
let child = completedWork.child;
while (child !== null) {
// 合并子节点的 lanes 和 childLanes 到 newChildLanes 中。
newChildLanes = mergeLanes(
newChildLanes,
mergeLanes(child.lanes, child.childLanes),
);
// ignore them.
// 使用按位与运算符 & 过滤掉非静态的标志(通过 StaticMask)。
subtreeFlags |= child.subtreeFlags & StaticMask;
subtreeFlags |= child.flags & StaticMask;
child.return = completedWork;
child = child.sibling;
}
completedWork.subtreeFlags |= subtreeFlags;
}
completedWork.childLanes = newChildLanes;
return didBailout;
}
<Tag>HostRoot
HostRoot
类型节点(即应用根节点)的核心逻辑,主要负责完成根节点渲染后的环境清理、状态同步和副作用标记。
case HostRoot: {
// 1、获取 FiberRoot 实例,React 应用的根对象,包含应用状态、优先级队列等核心信息。
const fiberRoot = (workInProgress.stateNode: FiberRoot);
//2、缓存处理
if (enableCache) {
let previousCache: Cache | null = null;
if (current !== null) {
previousCache = current.memoizedState.cache;
}
const cache: Cache = workInProgress.memoizedState.cache;
// 比较新旧缓存对象,若不同则标记 Passive 副作用(如 useEffect)
if (cache !== previousCache) {
// Run passive effects to retain/release the cache.
workInProgress.flags |= Passive;
}
// 清理缓存上下文栈
popCacheProvider(workInProgress, cache);
}
// 3、环境状态恢复
// 弹出过渡状态:结束当前渲染的过渡(如 startTransition)。
popRootTransition(workInProgress, fiberRoot, renderLanes);
// 弹出宿主容器:恢复 DOM 根节点上下文(见 popHostContainer 函数)
popHostContainer(workInProgress);
// 弹出遗留上下文:清理旧版 context API 的状态。
popTopLevelLegacyContextObject(workInProgress);
// 4、上下文状态同步
// 在渲染过程中收集的新上下文值,在此处应用到根节点。
if (fiberRoot.pendingContext) {
fiberRoot.context = fiberRoot.pendingContext;
fiberRoot.pendingContext = null;
}
//5、处理水合
// 处理首次渲染或无子节点的情况
if (current === null || current.child === null) {
// If we hydrated, pop so that we can delete any remaining children
// that weren't hydrated.
// popHydrationState:清理水合过程中的临时状态,并返回是否成功水合。
const wasHydrated = popHydrationState(workInProgress);
// 水合成功
if (wasHydrated) {
// emitPendingHydrationWarnings();
// 标记更新,可能用于处理残留的 DOM 差异。
// markUpdate(workInProgress);
} else {
// 未水合或水合失败的处理
if (current !== null) {
const prevState: RootState = current.memoizedState;
if (
// Check if this is a client root
// 非脱水状态(纯客户端渲染)
!prevState.isDehydrated ||
// Check if we reverted to client rendering (e.g. due to an error)
// 强制客户端渲染标志(如水合错误)
(workInProgress.flags & ForceClientRender) !== NoFlags
) {
// Snapshot 标志:触发 getSnapshotBeforeUpdate 生命周期(若适用)。
workInProgress.flags |= Snapshot;
// upgradeHydrationErrorsToRecoverable:将水合错误转换为可恢复错误,避免整页崩溃。
upgradeHydrationErrorsToRecoverable();
}
}
}
}
// 6、更新宿主容器与冒泡属性
// 更新宿主容器:生成 DOM 更新队列(如属性变化、子节点增删)。
updateHostContainer(current, workInProgress);
// 冒泡属性:向上传递子树的状态(如是否有副作用、优先级信息)。
bubbleProperties(workInProgress);
return null;
}
updateHostContainer
updateHostContainer
是 React 中处理宿主容器(如 DOM 根节点或 Portal 容器)更新的核心函数。当启用持久化渲染(supportsPersistence
)且需要克隆容器时,该函数会创建新的子节点集合,标记更新,并最终触发容器的子节点替换。
function updateHostContainer(current: null | Fiber, workInProgress: Fiber) {
// supportsPersistence:是否启用持久化渲染(如 React 18+ 的并发模式)。
if (supportsPersistence) {
// oesRequireClone:判断是否需要克隆容器(如子节点结构变化、属性更新等)。
if (doesRequireClone(current, workInProgress)) {
// 创建新子节点集合
const portalOrRoot: {
containerInfo: Container,
pendingChildren: ChildSet,
} = workInProgress.stateNode;
const container = portalOrRoot.containerInfo;
// 创建用于存储子节点的临时集合。
const newChildSet = createContainerChildSet();
// If children might have changed, we have to add them all to the set.
// appendAllChildrenToContainer将 workInProgress 的所有子节点添加到新集合。
appendAllChildrenToContainer(
newChildSet,
workInProgress,
/* needsVisibilityToggle */ false,
/* isHidden */ false,
);
portalOrRoot.pendingChildren = newChildSet;
// Schedule an update on the container to swap out the container.
// 标记容器需要更新,触发后续的 DOM 操作。
markUpdate(workInProgress);
// 准备容器的子节点更新,可能包括:
// 计算新旧子节点的差异。
// 准备插入 / 删除 / 移动等 DOM 操作队列。
finalizeContainerChildren(container, newChildSet);
}
}
}
工具函数之 doesRequireClone
doesRequireClone
函数用于判断是否需要克隆宿主容器(如 DOM 节点)以应用更新。
function doesRequireClone(current: null | Fiber, completedWork: Fiber) {
const didBailout = current !== null && current.child === completedWork.child;
// 若组件因 bailout 机制跳过渲染(如 React.memo 优化),直接返回 false(无需克隆)。
if (didBailout) {
return false;
}
// ChildDeletion 标志:表示子树中存在节点删除操作,需克隆容器以安全移除节点。
if ((completedWork.flags & ChildDeletion) !== NoFlags) {
return true;
}
// TODO: If we move the `doesRequireClone` call after `bubbleProperties`
// then we only have to check the `completedWork.subtreeFlags`.
let child = completedWork.child;
while (child !== null) {
// Cloned:节点需要被克隆。
// Visibility:节点可见性变化(如通过 Suspense 控制)。
// Placement:节点插入或移动。
// ChildDeletion:子节点删除。
// 持久化模式(enablePersistedModeClonedFlag 启用
const checkedFlags = enablePersistedModeClonedFlag
? Cloned | Visibility | Placement | ChildDeletion
// 传统模式:检查 MutationMask(包含 Placement、Update、Deletion 等基本变更)。
: MutationMask;
// child.flags:当前节点的变更标志。
// child.subtreeFlags:子树中所有节点的累积变更标志。
if (
(child.flags & checkedFlags) !== NoFlags ||
(child.subtreeFlags & checkedFlags) !== NoFlags
) {
return true;
}
child = child.sibling;
}
return false;
}
工具函数之 createContainerChildSet
createContainerChildSet
是 React 中用于创建子节点集合的工厂函数,主要服务于宿主容器(如 DOM 根节点或 Portal)的更新过程。
createContainerChildSet(): Array<Instance | TextInstance> {
return [];
},
工具函数之 appendAllChildrenToContainer
appendAllChildrenToContainer
是 React 渲染流程中的核心函数,用于将 Fiber 树中的子节点递归转换为实际渲染节点(如 DOM 元素)并添加到容器中。
function appendAllChildrenToContainer(
containerChildSet: ChildSet, // 目标容器子节点集合
workInProgress: Fiber, // 当前处理的 Fiber 节点
needsVisibilityToggle: boolean, // 是否需要控制可见性
isHidden: boolean, // 当前是否隐藏
) {
if (supportsPersistence) {
// We only have the top Fiber that was created but we need recurse down its
// children to find all the terminal nodes.
let node = workInProgress.child;
while (node !== null) {
// 节点类型处理
// 1、HostComponent:DOM 元素(如 <div>)。
if (node.tag === HostComponent) {
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
// This child is inside a timed out tree. Hide it.
const props = node.memoizedProps;
const type = node.type;
instance = cloneHiddenInstance(instance, type, props);
}
// 将实例添加到子节点集合中
appendChildToContainerChildSet(containerChildSet, instance);
// 2、处理文本
} else if (node.tag === HostText) {
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
// This child is inside a timed out tree. Hide it.
const text = node.memoizedProps;
instance = cloneHiddenTextInstance(instance, text);
}
appendChildToContainerChildSet(containerChildSet, instance);
// 3、处理HostPortal
} else if (node.tag === HostPortal) {
// Portal 节点不递归处理子节点(由 Portal 单独管理)
// 4、处理不可见组件
} else if (
node.tag === OffscreenComponent &&
node.memoizedState !== null
) {
const child = node.child;
if (child !== null) {
child.return = node;
}
// If Offscreen is not in manual mode, detached tree is hidden from user space.
const _needsVisibilityToggle = !isOffscreenManual(node);
appendAllChildrenToContainer(
containerChildSet,
node,
/* needsVisibilityToggle */ _needsVisibilityToggle,
/* isHidden */ true,
);
// 递归到子节点
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
node = (node: Fiber);
if (node === workInProgress) {
return;
}
// 回溯到父节点
while (node.sibling === null) {
if (node.return === null || node.return === workInProgress) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
}
}
工具函数之 appendChildToContainerChildSet
appendChildToContainerChildSet
是 React 内部用于将子节点添加到容器子节点集合的辅助函数。
appendChildToContainerChildSet(
childSet: Array<Instance | TextInstance>,
child: Instance | TextInstance,
): void {
childSet.push(child);
},
工具函数之
appendAllChildrenToContainer
appendAllChildrenToContainer
是 React 渲染流程中的核心函数,用于将 Fiber 树中的子节点递归转换为实际渲染节点(如 DOM 元素)并添加到容器中。该函数处理多种节点类型(组件、文本、Portal 等),支持可见性控制,并在持久化渲染模式下优化节点添加逻辑。
function appendAllChildrenToContainer(
containerChildSet: ChildSet, // 目标容器子节点集合
workInProgress: Fiber, // 当前处理的 Fiber 节点
needsVisibilityToggle: boolean, // 是否需要控制可见性
isHidden: boolean, // 当前是否隐藏
) {
if (supportsPersistence) {
// We only have the top Fiber that was created but we need recurse down its
// children to find all the terminal nodes.
let node = workInProgress.child;
while (node !== null) {
// 节点类型处理
// 1、HostComponent:DOM 元素(如 <div>)。
if (node.tag === HostComponent) {
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
// This child is inside a timed out tree. Hide it.
const props = node.memoizedProps;
const type = node.type;
instance = cloneHiddenInstance(instance, type, props);
}
appendChildToContainerChildSet(containerChildSet, instance);
// 2、处理文本
} else if (node.tag === HostText) {
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
// This child is inside a timed out tree. Hide it.
const text = node.memoizedProps;
instance = cloneHiddenTextInstance(instance, text);
}
appendChildToContainerChildSet(containerChildSet, instance);
// 3、处理HostPortal
} else if (node.tag === HostPortal) {
// Portal 节点不递归处理子节点(由 Portal 单独管理)
// 4、处理不可见组件
} else if (
node.tag === OffscreenComponent &&
node.memoizedState !== null
) {
const child = node.child;
if (child !== null) {
child.return = node;
}
// If Offscreen is not in manual mode, detached tree is hidden from user space.
const _needsVisibilityToggle = !isOffscreenManual(node);
appendAllChildrenToContainer(
containerChildSet,
node,
/* needsVisibilityToggle */ _needsVisibilityToggle,
/* isHidden */ true,
);
// 递归到子节点
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
node = (node: Fiber);
if (node === workInProgress) {
return;
}
// 回溯或处理兄弟节点
while (node.sibling === null) {
if (node.return === null || node.return === workInProgress) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
}
}
工具函数之
finalizeContainerChildren
finalizeContainerChildren
函数用于将新生成的子节点集合(newChildren
)关联到容器(container
)。
finalizeContainerChildren(
container: Container,
newChildren: Array<Instance | TextInstance>,
): void {
container.pendingChildren = newChildren;
if (
newChildren.length === 1 &&
newChildren[0].text === 'Error when completing root'
) {
// Trigger an error for testing purposes
throw Error('Error when completing root');
}
},
<Tag>HostHoistable
HostHoistable
类型的 Fiber 节点,主要用于优化和管理可提升的宿主环境组件(如 DOM 元素)。这类组件可能包含异步资源(如图片、脚本),需要特殊的预加载和挂起逻辑。代码根据组件是否包含资源(Resource
)以及是否处于更新阶段,选择不同的处理路径,确保资源预加载和组件渲染的高效性与正确性。
case HostHoistable: {
if (supportsResources) {
const type = workInProgress.type;
const nextResource: Resource | null = workInProgress.memoizedState;
// 初始化
if (current === null) {
// 标记更新
markUpdate(workInProgress);
if (nextResource !== null) {
// 处理资源类型
bubbleProperties(workInProgress);
preloadResourceAndSuspendIfNeeded(
workInProgress,
nextResource,
type,
newProps,
renderLanes,
);
return null;
} else {
// 处理普通实例
bubbleProperties(workInProgress);
preloadInstanceAndSuspendIfNeeded(
workInProgress,
type,
newProps,
renderLanes,
);
return null;
}
} else {
// This is an update.
if (nextResource) {
// This is a Resource
if (nextResource !== current.memoizedState) {
// 资源变化,触发更新和预加载
// we have a new Resource. we need to update
markUpdate(workInProgress);
// This must come at the very end of the complete phase.
bubbleProperties(workInProgress);
preloadResourceAndSuspendIfNeeded(
workInProgress,
nextResource,
type,
newProps,
renderLanes,
);
return null;
} else {
// This must come at the very end of the complete phase.
bubbleProperties(workInProgress);
// 资源未变化,清除挂起标志
workInProgress.flags &= ~MaySuspendCommit;
return null;
}
} else {
// 更新阶段且为普通实例
// This is an Instance
// We may have props to update on the Hoistable instance.
if (supportsMutation) {
const oldProps = current.memoizedProps;
if (oldProps !== newProps) {
markUpdate(workInProgress);
}
} else {
// We use the updateHostComponent path becuase it produces
// the update queue we need for Hoistables.
updateHostComponent(
current,
workInProgress,
type,
newProps,
renderLanes,
);
}
// This must come at the very end of the complete phase.
bubbleProperties(workInProgress);
preloadInstanceAndSuspendIfNeeded(
workInProgress,
type,
newProps,
renderLanes,
);
return null;
}
}
}
// Fall through
}
工具函数之 preloadResourceAndSuspendIfNeeded
preloadResourceAndSuspendIfNeeded
是 React 内部用于处理异步资源预加载的核心函数,主要针对 HostHoistable
类型的 Fiber 节点(如媒体元素、脚本等)。其核心逻辑是:尝试预加载资源,如果资源未就绪则挂起当前渲染,避免阻塞主线程。该函数实现了 React 的并发渲染特性,确保在资源加载期间页面保持响应,并根据配置决定是显示旧内容还是立即挂起。
function preloadResourceAndSuspendIfNeeded(
workInProgress: Fiber,
resource: Resource,
type: Type,
props: Props,
renderLanes: Lanes,
) {
// This is a fork of preloadInstanceAndSuspendIfNeeded, but for resources.
// mayResourceSuspendCommit 判断资源是否可能导致挂起。
if (!mayResourceSuspendCommit(resource)) {
// 若不可能挂起(如资源已缓存),清除挂起标志并直接返回。
workInProgress.flags &= ~MaySuspendCommit;
return;
}
// 标记可能挂起状态
workInProgress.flags |= MaySuspendCommit;
const isReady = preloadResource(resource);
// 资源未就绪
if (!isReady) {
if (shouldRemainOnPreviousScreen()) {
// 标记 ShouldSuspendCommit 标志,等待资源就绪后再提交更新。
workInProgress.flags |= ShouldSuspendCommit;
} else {
// 资源已就绪
// 立即调用 suspendCommit() 挂起当前渲染,触发 Suspense 边界的 fallback。
suspendCommit();
}
}
}
<Tag>HostSingleton
HostSingleton
类型的 Fiber 节点,用于表示必须在整个应用中唯一存在的宿主环境组件。
case HostSingleton: {
// 支持单例
if (supportsSingletons) {
// 弹出当前 Fiber 的宿主环境上下文。
popHostContext(workInProgress);
// 获取根应用节点
const rootContainerInstance = getRootHostContainer();
const type = workInProgress.type;
// 更新
if (current !== null && workInProgress.stateNode != null) {
// 突变模式
if (supportsMutation) {
const oldProps = current.memoizedProps;
if (oldProps !== newProps) {
// 标记更新
markUpdate(workInProgress);
}
} else {
updateHostComponent(
current,
workInProgress,
type,
newProps,
renderLanes,
);
}
} else {
// 初始化
if (!newProps) {
if (workInProgress.stateNode === null) {
throw new Error(
'We must have new props for new mounts. This error is likely ' +
'caused by a bug in React. Please file an issue.',
);
}
// This can happen when we abort work.
bubbleProperties(workInProgress);
return null;
}
// 获取上下文
const currentHostContext = getHostContext();
const wasHydrated = popHydrationState(workInProgress);
let instance: Instance;
// 服务端渲染
if (wasHydrated) {
// prepareToHydrateHostInstance(workInProgress, currentHostContext);
// // 复用现有 DOM 节点,避免重新创建。
// instance = workInProgress.stateNode;
} else {
// 客户端渲染
// 通过 resolveSingletonInstance 创建单例实例,并标记更新。
instance = resolveSingletonInstance(
type,
newProps,
rootContainerInstance,
currentHostContext,
true,
);
workInProgress.stateNode = instance;
markUpdate(workInProgress);
}
}
// 属性冒泡,将子节点的状态(如副作用标志)向上传播到父节点。
bubbleProperties(workInProgress);
// 结束当前 Fiber 的处理
return null;
}
// Fall through
}
工具函数之 resolveSingletonInstance
resolveSingletonInstance
是 React 内部用于获取或创建单例 DOM 元素的核心函数,专门处理那些在文档中必须唯一存在且不能被 React 直接创建的特殊元素(如 <html>
、<head>
、<body>
)。
function resolveSingletonInstance(
type: string,
props: Props,
rootContainerInstance: Container,
hostContext: HostContext,
validateDOMNestingDev: boolean,
): Instance {
// 获取document对象
const ownerDocument = getOwnerDocumentFromRootContainer(
rootContainerInstance,
);
switch (type) {
case 'html': {
const documentElement = ownerDocument.documentElement;
if (!documentElement) {
throw new Error(
'React expected an <html> element (document.documentElement) to exist in the Document but one was' +
' not found. React never removes the documentElement for any Document it renders into so' +
' the cause is likely in some other script running on this page.',
);
}
return documentElement;
}
case 'head': {
const head = ownerDocument.head;
if (!head) {
throw new Error(
'React expected a <head> element (document.head) to exist in the Document but one was' +
' not found. React never removes the head for any Document it renders into so' +
' the cause is likely in some other script running on this page.',
);
}
return head;
}
case 'body': {
const body = ownerDocument.body;
if (!body) {
throw new Error(
'React expected a <body> element (document.body) to exist in the Document but one was' +
' not found. React never removes the body for any Document it renders into so' +
' the cause is likely in some other script running on this page.',
);
}
return body;
}
default: {
throw new Error(
'resolveSingletonInstance was called with an element type that is not supported. This is a bug in React.',
);
}
}
}
<Tag>HostComponent
HostComponent
(如 DOM 元素)的核心逻辑,主要负责创建或更新实际的 DOM 节点。它根据节点是否已存在、是否来自服务端渲染水合等情况,选择不同的处理路径,并处理特殊属性(如自动聚焦)和预加载逻辑。
case HostComponent: {
// 退出当前宿主环境上下文栈
popHostContext(workInProgress);
// 获取组件类型,类如div,span
const type = workInProgress.type;
// 更新已存在的 DOM 节点
if (current !== null && workInProgress.stateNode != null) {
// 调用 updateHostComponent 更新 DOM 属性(如 className、style)。处理事件监听器的添加 / 移除。
updateHostComponent(
current,
workInProgress,
type,
newProps,
renderLanes,
);
// 首次渲染或新增
} else {
if (!newProps) {
// 错误处理:新节点必须有 props
if (workInProgress.stateNode === null) {
throw new Error(
'We must have new props for new mounts. This error is likely ' +
'caused by a bug in React. Please file an issue.',
);
}
// This can happen when we abort work.
bubbleProperties(workInProgress);
return null;
}
const currentHostContext = getHostContext();
const wasHydrated = popHydrationState(workInProgress);
if (wasHydrated) {
// prepareToHydrateHostInstance(workInProgress, currentHostContext);
} else {
// 纯客户端渲染逻辑
const rootContainerInstance = getRootHostContainer();
// 调用 createInstance 创建新 DOM 元素。
const instance = createInstance(
type,
newProps,
rootContainerInstance,
currentHostContext,
workInProgress,
);
markCloned(workInProgress);
// 通过 appendAllChildren 添加子元素。
appendAllChildren(instance, workInProgress, false, false);
workInProgress.stateNode = instance;
if (
finalizeInitialChildren(
instance,
type,
newProps,
currentHostContext,
)
) {
markUpdate(workInProgress);
}
}
}
// 属性冒泡
bubbleProperties(workInProgress);
// 预加载
preloadInstanceAndSuspendIfNeeded(
workInProgress,
workInProgress.type,
workInProgress.pendingProps,
renderLanes,
);
return null;
}
updateHostComponent
updateHostComponent
是 React 处理宿主组件(如 DOM 元素)更新的核心函数,根据渲染模式(突变模式或持久化模式)选择不同的更新策略。在突变模式下,直接标记节点更新;在持久化模式下,通过克隆实例实现无突变更新,并支持状态保留。
function updateHostComponent(
current: Fiber,
workInProgress: Fiber,
type: Type,
newProps: Props,
renderLanes: Lanes,
) {
// 突变模式下的处理(supportsMutation)
if (supportsMutation) {
const oldProps = current.memoizedProps;
// 比较新旧属性引用是否相同(浅比较)。
if (oldProps === newProps) {
return;
}
// 标记节点为更新状态
markUpdate(workInProgress);
// 持久化模式下的处理(supportsPersistence)
} else if (supportsPersistence) {
const currentInstance = current.stateNode;
const oldProps = current.memoizedProps;
// 通过 doesRequireClone 检查节点是否需要克隆。
const requiresClone = doesRequireClone(current, workInProgress);
if (!requiresClone && oldProps === newProps) {
workInProgress.stateNode = currentInstance;
return;
}
const currentHostContext = getHostContext();
let newChildSet = null;
if (requiresClone && passChildrenWhenCloningPersistedNodes) {
markCloned(workInProgress);
newChildSet = createContainerChildSet();
// If children might have changed, we have to add them all to the set.
appendAllChildrenToContainer(
newChildSet,
workInProgress,
/* needsVisibilityToggle */ false,
/* isHidden */ false,
);
}
// 调用 cloneInstance 创建新实例,保留旧状态。
const newInstance = cloneInstance(
currentInstance,
type,
oldProps,
newProps,
!requiresClone,
newChildSet,
);
if (newInstance === currentInstance) {
// 无需变更,复用
workInProgress.stateNode = currentInstance;
return;
} else {
// 标记为克隆节点
markCloned(workInProgress);
}
// 处理特殊属性(如自动聚焦)
if (
finalizeInitialChildren(newInstance, type, newProps, currentHostContext)
) {
markUpdate(workInProgress);
}
// 更新子节点
workInProgress.stateNode = newInstance;
if (!requiresClone) {
if (!enablePersistedModeClonedFlag) {
markUpdate(workInProgress);
}
} else if (!passChildrenWhenCloningPersistedNodes) {
// If children have changed, we have to add them all to the set.
appendAllChildren(
newInstance,
workInProgress,
/* needsVisibilityToggle */ false,
/* isHidden */ false,
);
}
}
}
createInstance
createInstance
方法,用于创建虚拟 DOM 元素的实例。该方法生成一个包含元素类型、属性和子节点信息的对象,并处理特殊属性(如 hidden
、src
)和文本内容。通过不可枚举属性存储内部状态,确保这些信息不会暴露给外部代码。
const sharedHostConfig = {
createInstance(
type: string,//元素的类型
props: Props,// 传递给元素的属性对象。
rootContainerInstance: Container,// 根容器实例,即渲染的目标容器。
hostContext: HostContext,// 当前渲染的宿主环境上下文。
internalInstanceHandle: Object,// 指向 React 内部 Fiber 节点的引用。
): Instance {
if (type === 'errorInCompletePhase') {
throw new Error('Error in host config.');
}
// 实例结构
const inst = {
id: instanceCounter++,
type: type,
children: [],
parent: -1,
// shouldSetTextContent:判断是否应将子节点作为文本内容处理。
text: shouldSetTextContent(type, props)
? // eslint-disable-next-line react-internal/safe-string-coercion
// computeText:处理文本内容(可能包括转义、格式化等)。
computeText((props.children: any) + '', hostContext)
: null,
prop: props.prop,
hidden: !!props.hidden,
context: hostContext,
};
// 为 suspensey-thing 类型的元素添加 src 属性。
if (type === 'suspensey-thing' && typeof props.src === 'string') {
inst.src = props.src;
}
// Hide from unit tests
// 将 id、parent、text 等属性设为不可枚举。
// 防止这些内部状态在 for...in 循环或 JSON.stringify 中暴露。
Object.defineProperty(inst, 'id', {value: inst.id, enumerable: false});
Object.defineProperty(inst, 'parent', {
value: inst.parent,
enumerable: false,
});
Object.defineProperty(inst, 'text', {
value: inst.text,
enumerable: false,
});
Object.defineProperty(inst, 'context', {
value: inst.context,
enumerable: false,
});
Object.defineProperty(inst, 'fiber', {
value: internalInstanceHandle,
enumerable: false,
});
return inst;
},
}
id
:唯一标识,用于内部跟踪。type
:元素类型(如 div
、span
)。children
:子节点数组。text
:文本内容(如果适用)。hidden
:是否隐藏(基于 props.hidden
)。
const inst = {
id: instanceCounter++,
type: type,
children: [],
parent: -1,
// shouldSetTextContent:判断是否应将子节点作为文本内容处理。
text: shouldSetTextContent(type, props)
? // eslint-disable-next-line react-internal/safe-string-coercion
// computeText:处理文本内容(可能包括转义、格式化等)。
computeText((props.children: any) + '', hostContext)
: null,
prop: props.prop,
hidden: !!props.hidden,
context: hostContext,
};
工具函数之 shouldSetTextContent
function shouldSetTextContent(type: string, props: Props): boolean {
if (type === 'errorInBeginPhase') {
throw new Error('Error in host config.');
}
return (
typeof props.children === 'string' ||
typeof props.children === 'number' ||
typeof props.children === 'bigint'
);
}
工具函数之
computeText
computeText
是一个文本处理函数,用于根据宿主环境上下文决定是否转换文本大小写。当上下文为 UPPERCASE_CONTEXT
时,将文本转换为大写;否则保持原文。
function computeText(rawText, hostContext) {
return hostContext === UPPERCASE_CONTEXT ? rawText.toUpperCase() : rawText;
}
const UPPERCASE_CONTEXT = {};
工具函数之 finalizeInitialChildren
finalizeInitialChildren
函数主要用于完成元素初始化后的最终处理。
setInitialProperties
设置元素的初始属性(如 className
、style
)。
function finalizeInitialChildren(
domElement: Instance,
type: string,
props: Props,
hostContext: HostContext,
): boolean {
setInitialProperties(domElement, type, props);
switch (type) {
case 'button':
case 'input':
case 'select':
case 'textarea':
return !!props.autoFocus;
case 'img':
return true;
default:
return false;
}
}
工具函数之 appendAllChildren
appendAllChildren
函数用于将 Fiber 树中的所有子节点挂载到父 DOM 节点上。它通过深度优先遍历 Fiber 树,将真实 DOM 节点(如 HostComponent
和 HostText
)按正确顺序添加到父容器中。该函数针对不同渲染模式(突变模式和持久化模式)进行了优化。
function appendAllChildren(
parent: Instance,// 指定子节点要挂载到的父容器。
workInProgress: Fiber,// 当前正在处理的 Fiber 节点,作为遍历起点。
needsVisibilityToggle: boolean, //指示是否需要根据 isHidden 参数调整子节点的可见性。
isHidden: boolean, // 当 needsVisibilityToggle 为 true 时,决定子节点是否应被隐藏。
) {
// 突变模式处理(supportsMutation)
if (supportsMutation) {
let node = workInProgress.child;
while (node !== null) {
// 处理当前节点
if (node.tag === HostComponent || node.tag === HostText) {
// 将 HostComponent(DOM 元素)或 HostText(文本节点)直接添加到父容器。
appendInitialChild(parent, node.stateNode);
} else if (
node.tag === HostPortal ||
(supportsSingletons ? node.tag === HostSingleton : false)
) {
// Portal 节点不直接添加到父容器,而是通过 Portal 机制挂载到其他容器
// 递归处理子节点
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
if (node === workInProgress) {
return;
}
// 回溯或处理兄弟节点
while (node.sibling === null) {
if (node.return === null || node.return === workInProgress) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
// 持久化模式处理(supportsPersistence)
} else if (supportsPersistence) {
// We only have the top Fiber that was created but we need recurse down its
// children to find all the terminal nodes.
let node = workInProgress.child;
while (node !== null) {
if (node.tag === HostComponent) {
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
// 当节点位于超时的 Suspense 边界内时,克隆节点并应用隐藏样式。
const props = node.memoizedProps;
const type = node.type;
instance = cloneHiddenInstance(instance, type, props);
}
//将 instance 直接添加到父容器。
appendInitialChild(parent, instance);
} else if (node.tag === HostText) {
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
const text = node.memoizedProps;
instance = cloneHiddenTextInstance(instance, text);
}
appendInitialChild(parent, instance);
} else if (node.tag === HostPortal) {
// Portal 节点不直接添加到父容器,而是通过 Portal 机制挂载到其他容器
} else if (
node.tag === OffscreenComponent &&
node.memoizedState !== null
) {
const child = node.child;
if (child !== null) {
child.return = node;
}
appendAllChildren(
parent,
node,
/* needsVisibilityToggle */ true,
/* isHidden */ true,
);
// 递归处理子节点
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
if (node === workInProgress) {
return;
}
// 回溯或处理兄弟节点
while (node.sibling === null) {
if (node.return === null || node.return === workInProgress) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
}
}
工具函数之 appendInitialChild
function appendInitialChild(
parentInstance: Instance,
child: Instance | TextInstance,
): void {
parentInstance.appendChild(child);
}
工具函数之 cloneHiddenInstance
const hostConfig = useMutation ? {
cloneHiddenInstance(
instance: Instance,
type: string,
props: Props,
): Instance {
const clone = cloneInstance(instance, type, props, props, true, null);
clone.hidden = true;
return clone;
},
}
工具函数之 cloneInstance
cloneInstance
是 React 内部用于克隆 DOM 元素实例的函数,主要用于在不改变原始实例的情况下创建一个具有新属性的副本
function cloneInstance(
instance: Instance,
type: string,
oldProps: Props,
newProps: Props,
keepChildren: boolean,
children: ?$ReadOnlyArray<Instance>,
): Instance {
// 实例克隆核心逻辑
const clone = {
id: instance.id,
type: type,
parent: instance.parent,
children: keepChildren ? instance.children : children ?? [],
text: shouldSetTextContent(type, newProps)
? computeText((newProps.children: any) + '', instance.context)
: null,
prop: newProps.prop,
hidden: !!newProps.hidden,
context: instance.context,
};
// 当元素类型为 suspensey-thing 且新属性包含 src 时,添加 src 属性到克隆实例。
if (type === 'suspensey-thing' && typeof newProps.src === 'string') {
clone.src = newProps.src;
}
// 不可枚举属性设置
// 将关键内部属性设为不可枚举,避免在遍历或序列化时暴露。
// 保持与原始实例的行为一致性。
Object.defineProperty(clone, 'id', {
value: clone.id,
enumerable: false,
});
Object.defineProperty(clone, 'parent', {
value: clone.parent,
enumerable: false,
});
Object.defineProperty(clone, 'text', {
value: clone.text,
enumerable: false,
});
Object.defineProperty(clone, 'context', {
value: clone.context,
enumerable: false,
});
hostCloneCounter++;
return clone;
}
工具函数之 cloneHiddenTextInstance
cloneHiddenTextInstance
方法,专门用于克隆文本节点并将其标记为隐藏状态。用在处理需要临时隐藏文本内容但保留其结构和上下文的场景时。
const hostConfig = useMutation ? {
cloneHiddenTextInstance(
instance: TextInstance,
text: string,
): TextInstance {
const clone = {
text: instance.text,
id: instance.id,
parent: instance.parent,
hidden: true,
context: instance.context,
};
// Hide from unit tests
Object.defineProperty(clone, 'id', {
value: clone.id,
enumerable: false,
});
Object.defineProperty(clone, 'parent', {
value: clone.parent,
enumerable: false,
});
Object.defineProperty(clone, 'context', {
value: clone.context,
enumerable: false,
});
return clone;
},
}
preloadInstanceAndSuspendIfNeeded
preloadInstanceAndSuspendIfNeeded
函数负责在元素实例化阶段预加载资源并决定是否需要挂起渲染。
function preloadInstanceAndSuspendIfNeeded(
workInProgress: Fiber,
type: Type,
props: Props,
renderLanes: Lanes,
) {
if (!maySuspendCommit(type, props)) {
// MaySuspendCommit:表示该 Fiber 节点可能会暂停提交操作。在 React 的并发模式下,渲染过程可能会被暂停和恢复
workInProgress.flags &= ~MaySuspendCommit;
return;
}
workInProgress.flags |= MaySuspendCommit;
const isReady = preloadInstance(type, props);
if (!isReady) {
if (shouldRemainOnPreviousScreen()) {
workInProgress.flags |= ShouldSuspendCommit;
} else {
suspendCommit();
}
}
}
工具函数之 preloadResource
preloadResource
是一个用于资源预加载控制的函数,主要决定特定资源是否需要暂停渲染(suspend)。核心逻辑是:当资源类型为样式表(stylesheet)且处于未加载状态时,函数返回 false
触发渲染暂停;否则返回 true
继续渲染。
function preloadResource(resource: Resource): boolean {
if (
resource.type === 'stylesheet' &&
(resource.state.loading & Settled) === NotLoaded
) {
// Return false to indicate this resource should suspend
return false;
}
// Return true to indicate this resource should not suspend
return true;
}
<Tag>HostText
HostText
类型节点(即文本节点)的核心逻辑,主要负责更新或创建文本节点实例。它会根据节点是否已存在、是否来自服务端渲染水合等情况,选择不同的处理路径,确保文本内容正确地反映到 DOM 中。
case HostText: {
// 获取新旧文本内容
const newText = newProps;
// 更新
if (current && workInProgress.stateNode != null) {
const oldText = current.memoizedProps;
// 调用 updateHostText 更新现有文本节点内容(如 setTextContent)。
updateHostText(current, workInProgress, oldText, newText);
// 首次渲染
} else {
// 处理新创建的文本节点
if (typeof newText !== 'string') {
if (workInProgress.stateNode === null) {
throw new Error(
'We must have new props for new mounts. This error is likely ' +
'caused by a bug in React. Please file an issue.',
);
}
// This can happen when we abort work.
}
// 获取当前渲染的根容器(如 DOM 中的 root 节点)。
const rootContainerInstance = getRootHostContainer();
// 获取宿主环境上下文
const currentHostContext = getHostContext();
// 处理服务端渲染水合状态
const wasHydrated = popHydrationState(workInProgress);
// 检查当前节点是否来自服务端渲染的 HTML。
if (wasHydrated) {
// prepareToHydrateHostTextInstance(workInProgress);
} else {
// 添加Cloned标记
markCloned(workInProgress);
// 创建文本实例
workInProgress.stateNode = createTextInstance(
newText,
rootContainerInstance,
currentHostContext,
workInProgress,
);
}
}
// 冒泡属性与完成处理
bubbleProperties(workInProgress);
return null;
}
updateHostText
updateHostText
是 React 处理文本节点更新的核心函数,根据渲染模式(突变模式或持久化模式)选择不同的更新策略。当文本内容发生变化时,突变模式直接标记更新,而持久化模式则创建新的文本实例并标记克隆。这一机制确保了在不同渲染模式下文本更新的高效性和正确性。
function updateHostText(
current: Fiber,
workInProgress: Fiber,
oldText: string,
newText: string,
) {
// 突变模式下的处理(supportsMutation)
if (supportsMutation) {
// If the text differs, mark it as an update. All the work in done in commitWork.
// 当新旧文本内容不一致时,标记节点为 Update。
if (oldText !== newText) {
markUpdate(workInProgress);
}
// 持久化模式下的处理(supportsPersistence)
} else if (supportsPersistence) {
if (oldText !== newText) {
// If the text content differs, we'll create a new text instance for it.
const rootContainerInstance = getRootHostContainer();
const currentHostContext = getHostContext();
markCloned(workInProgress);
// 创建新的文本实例
workInProgress.stateNode = createTextInstance(
newText,
rootContainerInstance,
currentHostContext,
workInProgress,
);
// 确保父节点知道子节点已变更
if (!enablePersistedModeClonedFlag) {
// We'll have to mark it as having an effect, even though we won't use the effect for anything.
// This lets the parents know that at least one of their children has changed.
markUpdate(workInProgress);
}
} else {
// 文本未变化,复用现有实例
workInProgress.stateNode = current.stateNode;
}
}
}
工具函数之 markUpdate
function markUpdate(workInProgress: Fiber) {
workInProgress.flags |= Update;
}
工具函数之 markCloned
function markCloned(workInProgress: Fiber) {
if (supportsPersistence && enablePersistedModeClonedFlag) {
// 添加 Cloned 标志(flags |= Cloned)。
workInProgress.flags |= Cloned;
}
}
工具函数之
getRootHostContainer
getRootHostContainer
是 React 渲染系统中的基础函数,用于获取当前渲染上下文的根宿主容器。在浏览器环境中,这通常对应于 ReactDOM.render
或 ReactDOM.createRoot
指定的 DOM 节点(如 <div id="root"></div>
)。
function getRootHostContainer(): Container {
const rootInstance = requiredContext(rootInstanceStackCursor.current);
return rootInstance;
}
const rootInstanceStackCursor: StackCursor<Container | null> = createCursor(null);
function createCursor<T>(defaultValue: T): StackCursor<T> {
return {
current: defaultValue,
};
}
function requiredContext<Value>(c: Value | null): Value {
return (c: any);
}
工具函数之
getHostContext
getHostContext()
是 React 渲染系统中的核心函数,用于获取当前宿主环境的上下文信息。这些信息包括命名空间(如 HTML/SVG)、样式作用域、容器配置等,是正确创建和渲染 DOM 元素的关键依据。通过维护一个上下文栈,React 能够在嵌套渲染(如 SVG 内部元素)时动态切换环境配置,确保元素正确渲染。
function getHostContext(): HostContext {
const context = requiredContext(contextStackCursor.current);
return context;
}
const contextStackCursor: StackCursor<Object> =
createCursor(emptyContextObject);
const emptyContextObject: {} = {};
createTextInstance
createTextInstance
是 React 渲染系统中用于创建文本节点的核心函数。它通过宿主环境(如浏览器 DOM)提供的 API 创建实际的文本节点,并建立该节点与 React 内部 Fiber 节点的映射关系。这一过程是将虚拟 DOM 转换为真实 DOM 的关键步骤
function createTextInstance(
text: string,
rootContainerInstance: Container,
hostContext: HostContext,
internalInstanceHandle: Object,
): TextInstance {
// 创建新文本节点,调用 document.createTextNode(text) 创建实际的文本节点。
const textNode: TextInstance = getOwnerDocumentFromRootContainer(
rootContainerInstance,
).createTextNode(text);
// 建立 Fiber 节点与 DOM 节点的映射
precacheFiberNode(internalInstanceHandle, textNode);
return textNode;
}
工具函数之 getOwnerDocumentFromRootContainer
document
对象。
function getOwnerDocumentFromRootContainer(
rootContainerElement: Element | Document | DocumentFragment,
): Document {
return rootContainerElement.nodeType === DOCUMENT_NODE
? (rootContainerElement: any)
: rootContainerElement.ownerDocument;
}
工具函数之 precacheFiberNode
function precacheFiberNode(
hostInst: Fiber,
node: Instance | TextInstance | SuspenseInstance | ReactScopeInstance,
): void {
(node: any)[internalInstanceKey] = hostInst;
}
const randomKey = Math.random().toString(36).slice(2);
const internalInstanceKey = '__reactFiber$' + randomKey;
HostPortal
类型的 Fiber 节点,用于管理通过 ReactDOM.createPortal 创建的 Portal 组件。Portal 允许将子组件渲染到 DOM 树的不同位置(如独立的模态框、悬浮层),但保持与父组件的上下文关系。
case HostPortal:
// 从上下文栈中弹出当前 Portal 的容器信息。
popHostContainer(workInProgress);
// 比较新旧 Portal 容器的属性差异。标记需要执行的副作用(如属性更新、事件绑定)。
updateHostContainer(current, workInProgress);
// 首次挂载处理
if (current === null) {
//确保目标容器存在且可访问。注册 Portal 相关的事件处理(如点击穿透)。应用初始样式或动画。
preparePortalMount(workInProgress.stateNode.containerInfo);
}
// 属性冒泡,将 Portal 子树的状态(如副作用标志、优先级)传播到父节点。
bubbleProperties(workInProgress);
return null;
工具函数之 preparePortalMount
function preparePortalMount(portalInstance: Instance): void {
listenToAllSupportedEvents(portalInstance);
}
工具函数之 listenToAllSupportedEvents
selectionchange
事件会进行特殊处理,因为该事件不会冒泡,需要绑定到 document
对象上。 (详细的后续写一篇记录react合成事件)
function listenToAllSupportedEvents(rootContainerElement: EventTarget) {
// 检查 rootContainerElement 是否已经添加了事件监听器。如果没有,则将 listeningMarker 作为属性添加到 rootContainerElement 上,并将其值设为 true,表示已经添加了事件监听器。
if (!(rootContainerElement: any)[listeningMarker]) {
(rootContainerElement: any)[listeningMarker] = true;
// allNativeEvents 是一个集合,包含了 React 支持的所有原生事件。
// 遍历所有支持的原生事件
allNativeEvents.forEach(domEventName => {
if (domEventName !== 'selectionchange') {
if (!nonDelegatedEvents.has(domEventName)) {
listenToNativeEvent(domEventName, false, rootContainerElement);
}
listenToNativeEvent(domEventName, true, rootContainerElement);
}
});
// 获取顶层document对象
const ownerDocument =
(rootContainerElement: any).nodeType === DOCUMENT_NODE
? rootContainerElement
: (rootContainerElement: any).ownerDocument;
if (ownerDocument !== null) {
// The selectionchange event also needs deduplication
// but it is attached to the document.
if (!(ownerDocument: any)[listeningMarker]) {
(ownerDocument: any)[listeningMarker] = true;
listenToNativeEvent('selectionchange', false, ownerDocument);
}
}
}
}
全局常量(根节点状态)
type RootExitStatus = 0 | 1 | 2 | 3 | 4 | 5 | 6;
const RootInProgress = 0; // 根节点正在进行渲染
const RootFatalErrored = 1; // 渲染过程中发生致命错误,无法恢复。
const RootErrored = 2; //渲染过程中发生可恢复的错误。
const RootSuspended = 3; // 渲染被挂起,等待异步资源(如数据或代码)。
const RootSuspendedWithDelay = 4; // 渲染被挂起,但设置了延迟显示加载状态。
const RootCompleted = 5; // 渲染成功完成,所有工作已提交到 DOM。
const RootDidNotComplete = 6; // 渲染未完成,可能被更高优先级的更新中断。
全局常量(组件类型)
FiberTag
)。每个常量对应一种特定的组件或节点类型。
export const FunctionComponent = 0;
export const ClassComponent = 1;
export const HostRoot = 3; // Root of a host tree. Could be nested inside another node.
export const HostPortal = 4; // A subtree. Could be an entry point to a different renderer.
export const HostComponent = 5;
export const HostText = 6;
export const Fragment = 7;
export const Mode = 8;
export const ContextConsumer = 9;
export const ContextProvider = 10;
export const ForwardRef = 11;
export const Profiler = 12;
export const SuspenseComponent = 13;
export const MemoComponent = 14;
export const SimpleMemoComponent = 15;
export const LazyComponent = 16;
export const IncompleteClassComponent = 17;
export const DehydratedFragment = 18;
export const SuspenseListComponent = 19;
export const ScopeComponent = 21;
export const OffscreenComponent = 22;
export const LegacyHiddenComponent = 23;
export const CacheComponent = 24;
export const TracingMarkerComponent = 25;
export const HostHoistable = 26;
export const HostSingleton = 27;
export const IncompleteFunctionComponent = 28;
export const Throw = 29;
全局常量(节点的状态和操作位掩码)
// 无操作(初始状态)。
const NoFlags = /* */ 0b0000000000000000000000000000;
// 组件已执行工作(用于优化)。
const PerformedWork = /* */ 0b0000000000000000000000000001;
// 需要插入或移动 DOM 节点。
const Placement = /* */ 0b0000000000000000000000000010;
// 组件捕获到错误(用于错误边界)。
const DidCapture = /* */ 0b0000000000000000000010000000;
// 需要重置节点内容(如文本节点内容完全改变)。
const Hydrating = /* */ 0b0000000000000001000000000000;
// You can change the rest (and add more).
// 需要更新 DOM 节点属性(如 props 变化)。
const Update = /* */ 0b0000000000000000000000000100;
// Fiber 被克隆(如列表重排序时复用节点)。
const Cloned = /* */ 0b0000000000000000000000001000;
// 需要删除子节点。
const ChildDeletion = /* */ 0b0000000000000000000000010000;
// 需要重置节点内容(如文本节点内容完全改变)。
const ContentReset = /* */ 0b0000000000000000000000100000;
// 需要执行回调(如 useEffect、useLayoutEffect)。
const Callback = /* */ 0b0000000000000000000001000000;
/* Used by DidCapture: 0b0000000000000000000010000000; */
// 强制客户端渲染(如 SSR 水合失败)。
const ForceClientRender = /* */ 0b0000000000000000000100000000;
// 需要处理 ref 关联或解关联。
const Ref = /* */ 0b0000000000000000001000000000;
// 需要捕获 DOM 快照(如 getSnapshotBeforeUpdate)。
const Snapshot = /* */ 0b0000000000000000010000000000;
// 表示存在被动副作用(如 useEffect),需要异步执行。
const Passive = /* */ 0b0000000000000000100000000000;
/* Used by Hydrating: 0b0000000000000001000000000000; */
// 组件可见性变化(如 Suspense 显示 / 隐藏)。
const Visibility = /* */ 0b0000000000000010000000000000;
// 状态一致性标记(用于并发模式)。
const StoreConsistency = /* */ 0b0000000000000100000000000000;
全局常量
ref
相关的静态状态。在 React 中,ref
用于访问 DOM 节点或组件实例,这个标志可能表示 ref
相关的操作或状态是静态的,不需要在每次渲染时重新处理。useEffect
钩子中的某些操作,这个标志可能表示这些副作用的状态是静态的。Fiber
节点可能会暂停提交操作。在 React 的并发模式下,渲染过程可能会被暂停和恢复,这个标志用于标记那些可能会导致提交操作暂停的节点。
const StaticMask =
LayoutStatic | PassiveStatic | RefStatic | MaySuspendCommit;
const RefStatic = /* */ 0b0000001000000000000000000000;
const LayoutStatic = /* */ 0b0000010000000000000000000000;
const PassiveStatic = /* */ 0b0000100000000000000000000000;
const MaySuspendCommit = /* */ 0b0001000000000000000000000000;