const APP = () => (
<div>
<span></span>
<span></span>
</div>
)
ReactDom.render(<APP/>, document.querySelector('#root'))
渲染以上组件得到的 fiber tree
:
客户端首次渲染指的是调用 ReactDOM.render
方法将 React
元素挂载到 dom
元素上,结合源码,下面依次列举了执行 render
时的函数调用栈。
render
调用 ReactDOM.render
方法,该方法接收三个参数。
element
, React 元素,通过 createElment() 方法创建container
,容器 dom 元素callback
返回 legacyRenderSubtreeIntoContainer
方法执行结果。
由 DOMContainer
的定义可以看到,container
可以是元素和文档,它可以有一个类型为 RootType
的 _reactRootContainer
属性。
type DOMContainer =
| (Element & {
_reactRootContainer: ?RootType,
})
| (Document & {
_reactRootContainer: ?RootType,
});
export function render(
element: React$Element<any>,
container: DOMContainer,
callback: ?Function,
) {
// 省略代码
return legacyRenderSubtreeIntoContainer(
null,
element,
container,
false,
callback,
);
}
legacyRenderSubtreeIntoContainer
该方法接受以下参数:
parentComponent
,首次渲染为 nullchildren
,render 函数接收的 element 参数container
,render 函数接收的 container 参数forceHydrate
,true
表示服务端渲染,这里应为false
callback
,render 函数接收的 callback 参数
返回一个 root 实例,暂且不管它。
首次渲染时,调用 legacyCreateRootFromDOMContainer
方法生成 RootType
对象。由 RootType
定义可以看到,该对象的 _internalRoot
属性是一个 FiberRoot
对象,同时它还有两个方法 render
、unmount
。
type RootType = {
render(children: ReactNodeList, callback: ?() => mixed): void,
unmount(callback: ?() => mixed): void,
_internalRoot: FiberRoot,
};
function legacyRenderSubtreeIntoContainer(
parentComponent: ?React$Component<any, any>,
children: ReactNodeList,
container: DOMContainer,
forceHydrate: boolean,
callback: ?Function,
) {
// 省略代码
let root: RootType = (container._reactRootContainer: any); // 首次渲染为 undefined
let fiberRoot;
if (!root) {
// Initial mount
// 首次加载,为container设置_reactRootContainer属性,表示该节点为root节点
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
container,
forceHydrate,
);
fiberRoot = root._internalRoot;
// 省略 callback 相关代码
// Initial mount should not be batched.
// 首次加载时,指定不使用 batchedUpdates,因为这是初次渲染,需要尽快完成。
unbatchedUpdates(() => {
updateContainer(children, fiberRoot, parentComponent, callback);
});
} else {
// 省略非首次渲染代码
}
return getPublicRootInstance(fiberRoot);
}
legacyCreateRootFromDOMContainer
该方法接收以下参数:
container
,容器 dom 节点forceHydrate
,首次渲染为 false
返回一个 RootType
类型的对象。
function legacyCreateRootFromDOMContainer(
container: DOMContainer,
forceHydrate: boolean,
): RootType {
var shouldHydrate = forceHydrate || shouldHydrateDueToLegacyHeuristic(container); // 首次加载 shouldHydrate 为false
// 省略验证代码
return createLegacyRoot(
container,
shouldHydrate
? {
hydrate: true,
}
: undefined,
);
}
createLegacyRoot
该方法接收两个参数:
container
options
,首次渲染为undefined
,这个用于服务端渲染配置,可以不用管
返回 RootType
类型对象
type RootOptions = {
hydrate?: boolean,
hydrationOptions?: {
onHydrated?: (suspenseNode: Comment) => void,
onDeleted?: (suspenseNode: Comment) => void,
},
};
export function createLegacyRoot(
container: DOMContainer,
options?: RootOptions,
): RootType {
return new ReactDOMBlockingRoot(container, LegacyRoot, options);
}
ReactDOMBlockingRoot
该构造函数接收以下参数:
container
,容器 dom 节点tag
,节点类型,首次渲染传入了LegacyRoot
常量表明这是一个根节点options
,首次渲染传入undefined
使用 new
关键字调用该构造函数得到实例并设置了 _internalRoot
属性。这里的 RootTag
定义了三种类型,分别用 0
、1
、2
表示。
type RootTag = 0 | 1 | 2;
const LegacyRoot = 0;
const BlockingRoot = 1;
const ConcurrentRoot = 2;
function ReactDOMBlockingRoot(
container: DOMContainer,
tag: RootTag,
options: void | RootOptions,
) {
this._internalRoot = createRootImpl(container, tag, options);
}
createRootImpl
该方法接收以下参数:
container
,容器 dom 节点tag
,节点类型,首次渲染为LegacyRoot
options
,首次渲染为undefined
返回调用createContainer
方法的结果。
function createRootImpl(
container: DOMContainer,
tag: RootTag,
options: void | RootOptions,
) {
// 省略代码
const root = createContainer(container, tag, hydrate, hydrationCallbacks); // hydrate = false, hydrationCallbacks = null
markContainerAsRoot(root.current, container);
// 省略代码
return root;
}
createContainer
该方法接收以下参数:
containerInfo
,容器 dom 节点tag
,节点类型,首次渲染为legacyRoot
hydrate
, 首次渲染为false
hydrationCallbacks
,首次渲染为null
返回调用 createFiberRoot
方法的结果。FiberRoot
对象由一系列的属性构成,OpaqueRoot
等同于 FiberRoot
。
type FiberRoot = {
...BaseFiberRootProperties,
...ProfilingOnlyFiberRootProperties,
...SuspenseCallbackOnlyFiberRootProperties,
}
type OpaqueRoot = FiberRoot
export function createContainer(
containerInfo: Container,
tag: RootTag,
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
): OpaqueRoot {
return createFiberRoot(containerInfo, tag, hydrate, hydrationCallbacks); // tag = 0,hydrate = false, hydrationCallbacks = null
}
createFiberRoot
该方法接收以下参数:
containerInfo
,容器 dom 节点tag
,节点类型,首次渲染为legacyRoot
hydrate
, 首次渲染为false
hydrationCallbacks
,首次渲染为false
返回一个 FiberRootNode
实例。
该方法先实例化 FiberRootNode
对象得到 root
,然后调用 createHostRootFiber
方法得到 uninitializedFiber
对象,将该对象赋值给 root.current
,又将该对象的 stateNode
属性指向 root
。
function createFiberRoot(
containerInfo: any,
tag: RootTag,
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
): FiberRoot {
const root: FiberRoot = (new FiberRootNode(containerInfo, tag, hydrate): any); // tag = 0,hydrate = false
// 省略代码
var uninitializedFiber = createHostRootFiber(tag);
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;
return root;
}
FiberRootNode
FiberRootNode
构造函数接收以下参数:
containerInfo
tag
hydrate
function FiberRootNode(containerInfo, tag, hydrate) {
// 首次加载,hydrate = false
// fiber 类型
this.tag = tag;
// 当前的 fiber 对象
this.current = null;
// 容器 dom 节点
this.containerInfo = containerInfo;
this.pendingChildren = null;
this.pingCache = null;
this.finishedExpirationTime = NoWork;
this.finishedWork = null;
this.timeoutHandle = noTimeout;
this.context = null;
this.pendingContext = null;
this.hydrate = hydrate;
this.callbackNode = null;
this.callbackPriority = NoPriority;
this.firstPendingTime = NoWork;
this.firstSuspendedTime = NoWork;
this.lastSuspendedTime = NoWork;
this.nextKnownPendingLevel = NoWork;
this.lastPingedTime = NoWork;
this.lastExpiredTime = NoWork;
if (enableSchedulerTracing) {
this.interactionThreadID = tracing.unstable_getThreadID();
this.memoizedInteractions = new Set();
this.pendingInteractionMap = new Map();
}
if (enableSuspenseCallback) {
this.hydrationCallbacks = null;
}
}
createHostRootFiber
该方法接收以下参数:
tag
,首次渲染为0
返回一个 Fiber
类型的对象。Fiber
类型的对象其实就是下面 FiberNode
构造函数创建出来的实例。
function createHostRootFiber(tag: RootTag): Fiber {
var mode;
if (tag === ConcurrentRoot) { // ConcurrentRoot 为 2
mode = ConcurrentMode | BlockingMode | StrictMode;
} else if (tag === BlockingRoot) { // BlockingRoot 为 1
mode = BlockingMode | StrictMode;
} else {
mode = NoMode; // NoMode 为 0
}
if (enableProfilerTimer && isDevToolsPresent) { // 是否启用了 devTool
// Always collect profile timings when DevTools are present.
// This enables DevTools to start capturing timing at any point–
// Without some nodes in the tree having empty base times.
mode |= ProfileMode; // ProfileMode 为 8
}
return createFiber(HostRoot, null, null, mode); // HostRoot = 3
}
createFiber
返回一个 FiberNode
实例。代码中明确定义了 22 种WorkTag,在FiberNode实例中用tag标识。
type WorkTag = | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21;
const FunctionComponent = 0; // 函数组件
const ClassComponent = 1; // 类组件
const IndeterminateComponent = 2; // Before we know whether it is n or class
const HostRoot = 3; // React应用的根节点
const HostPortal = 4; // 跨层级渲染的Portal容器(通过 ReactDOM.createPortal 创建)
const HostComponent = 5; // 原生DOM元素节点
const HostText = 6; // 文本节点
const Fragment = 7; // <React.Fragment> 组件
const Mode = 8; // 严格模式标记(如 <React.StrictMode> )
const ContextConsumer = 9; // Context消费者(如 useContext 或 <Context.Consumer> )
const ContextProvider = 10; // Context提供者(如 <Context.Provider> )
const ForwardRef = 11; // 转发Ref组件(如 React.forwardRef )
const Profiler = 12; // 性能分析组件(如 <Profiler> )
const SuspenseComponent = 13; // 异步加载边界(如 <Suspense fallback={...}> )
const MemoComponent = 14; // 普通记忆组件(如 React.memo(Component) )
const SimpleMemoComponent = 15; // 无自定义比较函数的 React.memo 组件
const LazyComponent = 16; // 懒加载组件(通过 React.lazy() 创建)
const IncompleteClassComponent = 17; // 渲染过程中未完成更新的类组件(中间状态)
const DehydratedFragment = 18; // 服务端渲染(SSR)中的脱水片段(用于客户端注水过程)
const SuspenseListComponent = 19; // 管理多个Suspense组件的加载顺序(如 <SuspenseList> )
const FundamentalComponent = 20; // 对应的WorkTag类型(数值为20)表示一种 实验性底层组件类型 ,主要用于支持与原生UI库(如React Native、Flutter等)的深度集成
const ScopeComponent = 21; // 实验性作用域组件(与React作用域API相关)
var createFiber = function (
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
return new FiberNode(tag, pendingProps, key, mode); // tag = 3, pendingProps = null, key = null
};
FiberNode
FiberNode
构造函数。
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
// Instance
this.tag = tag; // 标记Fiber节点的具体类型,React内部定义了22种WorkTag。如0-函数组件、1-类组件、5-原生DOM节点、7-Fragment、16-懒加载组件等。
this.key = key; // 标识同一层节点的唯一性,优化列表渲染时的diff算法效率。
this.elementType = null; // 组件原始类型标识,对于高阶组件(如 React.memo 包裹的组件),此属性保留未包装前的类型,与 type 属性可能不同(例如 memo 后的函数组件)
this.type = null; // 组件类型。函数组件指向函数本身、类组件指向类的构造函数、原生DOM为标签名
this.stateNode = null; // 保存与Fiber关联的实例,类组件指向组件实例(this)、原生DOM节点指向真实DOM对象。
this.return = null; // 指向父节点
this.child = null; // 指向第一个子节点
this.sibling = null; // 指向右侧兄弟节点
this.index = 0; // 表示在列表中的位置
this.ref = null; // 提供直接操作底层DOM或组件实例的能力
this.pendingProps = pendingProps; // 待应用的新属性(如父组件传入的props)
this.memoizedProps = null; // 上一次渲染使用的属性
this.updateQueue = null; // 存储状态更新队列,类组件-存放 setState 触发的更新对象,函数组件-保存 useEffect 的副作用链表
this.memoizedState = null; // 保存组件状态,类组件-this.state,函数组件-Hooks链表
this.dependencies = null; // 存储当前组件依赖的上下文(Context)或外部资源,用于追踪 Context API 或事件订阅的变更。例如,当组件使用 useContext 时,该属性会记录关联的上下文对象。
this.mode = mode; // 描述Fiber树的渲染模式,如ConcurrentMode-支持异步渲染与优先级调度,BlockingMode-过渡模式(介于同步与并发模式之间),StrictMode-严格模式(检测潜在问题)
this.effectTag = NoEffect;
this.firstEffect = null; // 形成副作用链表(Effect List),用于批量处理DOM操作。指向子树中第一个需要处理的副作用节点
this.nextEffect = null; // 连接下一个副作用节点(用于遍历)
this.lastEffect = null; // 指向最后一个副作用节点
this.expirationTime = NoWork; // 标记任务过期时间(后续版本中改为 lanes 优先级模型),数值越大优先级越高(如用户输入事件优先级为 Sync ),用于调度器判断任务是否应被中断或抢占
this.childExpirationTime = NoWork;
this.alternate = null; // 指向另一棵Fiber树中的对应节点,用于实现双缓存。
// 省略相关代码
}
markContainerAsRoot
该方法接收两个参数:
hostRoot
node
该方法是将 hostRoot
挂载到 node
上面。
function markContainerAsRoot(hostRoot, node) {
node[internalContainerInstanceKey] = hostRoot;
}
updateContainer
该方法处理更新任务,包括创建 update
对象、关联 update
到 fiber
对象、触发任务调度。
type ReactEmpty = null | void | boolean;
type ReactNodeList = ReactEmpty | React$Node;
type ExpirationTime = number;
function updateContainer(
element: ReactNodeList,
container: OpaqueRoot,
parentComponent: ?React$Component<any, any>,
callback: ?Function,
): ExpirationTime {
const current = container.current;
const currentTime = requestCurrentTimeForUpdate();
// 省略代码
const suspenseConfig = requestCurrentSuspenseConfig(); // null
const expirationTime = computeExpirationForFiber(
currentTime,
current,
suspenseConfig,
);
// 省略代码
const context = getContextForSubtree(parentComponent); // 返回 emptyContextObject,为空对象
if (container.context === null) {
container.context = context;
} else {
// 省略代码
}
// 省略代码
const update = createUpdate(expirationTime, suspenseConfig);
// Caution: React DevTools currently depends on this property
// being called "element".
update.payload = {element};
// 省略代码
enqueueUpdate(current, update); // 将 update 设置到 current 的 updateQueue对象中
scheduleWork(current, expirationTime);
return expirationTime;
}
createUpdate
该方法接收以下参数:
expirationTime
suspenseConfig
返回一个 Update
类型的对象。
type Update<State> = {
expirationTime: ExpirationTime,
suspenseConfig: null | SuspenseConfig,
tag: 0 | 1 | 2 | 3,
payload: any,
callback: (() => mixed) | null,
next: Update<State> | null,
nextEffect: Update<State> | null,
//DEV only
priority?: ReactPriorityLevel,
};
export function createUpdate(
expirationTime: ExpirationTime,
suspenseConfig: null | SuspenseConfig,
): Update<*> {
let update: Update<*> = {
expirationTime,
suspenseConfig,
tag: UpdateState,
payload: null,
callback: null,
next: null,
nextEffect: null,
};
if (__DEV__) {
update.priority = getCurrentPriorityLevel(); // 返回 NormalPriority,97
}
return update;
}
enqueueUpdate
该方法接收以下参数:
fiber
update
该方法的作用是将 update
对象关联到 fiber.updateQueue
。
function enqueueUpdate<State>(fiber: Fiber, update: Update<State>) {
var alternate = fiber.alternate; // 初始化时,fiber.alternate 为 null
var queue1;
var queue2;
if (alternate === null) {
// There's only one fiber.
queue1 = fiber.updateQueue;
queue2 = null;
if (queue1 === null) {
queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); // 传入上一次渲染后的state
}
} else {
// 省略代码
}
if (queue2 === null || queue1 === queue2) {
// There's only a single queue.
appendUpdateToQueue(queue1, update);
} else {
// 省略代码
}
// 省略代码
}
createUpdateQueue
该方法接收以下参数:
baseState
,上一次渲染结束后的state对象
创建 queue
对象。
type UpdateQueue<State> = {
baseState: State,
firstUpdate: Update<State> | null,
lastUpdate: Update<State> | null,
firstCapturedUpdate: Update<State> | null,
lastCapturedUpdate: Update<State> | null,
firstEffect: Update<State> | null,
lastEffect: Update<State> | null,
firstCapturedEffect: Update<State> | null,
lastCapturedEffect: Update<State> | null,
};
function createUpdateQueue<State>(baseState: State): UpdateQueue<State> {
const queue: UpdateQueue<State> = {
baseState,
firstUpdate: null,
lastUpdate: null,
firstCapturedUpdate: null,
lastCapturedUpdate: null,
firstEffect: null,
lastEffect: null,
firstCapturedEffect: null,
lastCapturedEffect: null,
};
return queue;
}
appendUpdateToQueue
该方法接收以下参数:
queue
update
function appendUpdateToQueue<State>(
queue: UpdateQueue<State>,
update: Update<State>,
) {
if (queue.lastUpdate === null) {
// 首次渲染
queue.firstUpdate = queue.lastUpdate = update;
} else {
// 省略代码
}
}
scheduleUpdateOnFiber
scheduleWork
等于 scheduleUpdateOnFiber
该方法接收以下参数:
fiber
expirationTime
function scheduleUpdateOnFiber(
fiber: Fiber,
expirationTime: ExpirationTime
) {
// 省略代码
checkForNestedUpdates(); // 没有嵌套的 update
var root = markUpdateTimeFromFiberToRoot(fiber, expirationTime);
// 省略代码
// priority as an argument to that function and this one.
var priorityLevel = getCurrentPriorityLevel(); // 返回 NormalPriority, 97
if (expirationTime === Sync) {
if ( // Check if we're inside unbatchedUpdates
(executionContext & LegacyUnbatchedContext) !== NoContext && // Check if we're not already rendering
(executionContext & (RenderContext | CommitContext)) === NoContext) {
// Register pending interactions on the root to avoid losing traced interaction data.
schedulePendingInteractions(root, expirationTime); // 只有对root调用该方法,什么都没做
performSyncWorkOnRoot(root);
} else {
// 省略代码
}
} else {
// 省略代码
}
// 省略代码
}
markUpdateTimeFromFiberToRoot
该方法接收以下参数:
fiber
expirationTime
function markUpdateTimeFromFiberToRoot(fiber, expirationTime) {
// 初始化时 fiber.expirationTime 为 0,将它更新为计算出来的 expirationTime
if (fiber.expirationTime < expirationTime) {
fiber.expirationTime = expirationTime;
}
var alternate = fiber.alternate; // 初始化时 fiber.alternate 为 null
if (alternate !== null && alternate.expirationTime < expirationTime) {
alternate.expirationTime = expirationTime;
} // Walk the parent path to the root and update the child expiration time.
var node = fiber.return; // 初始化时 fiber.return 为 null
var root = null;
if (node === null && fiber.tag === HostRoot) {
root = fiber.stateNode;
} else {
// 省略代码
}
if (root !== null) {
// 省略代码
markRootUpdatedAtTime(root, expirationTime);
}
return root;
}
markRootUpdatedAtTime
设置父节点跟time相关的属性为 expirationTime
function markRootUpdatedAtTime(root, expirationTime) {
// Update the range of pending times
var firstPendingTime = root.firstPendingTime; // 首次为 0
if (expirationTime > firstPendingTime) {
root.firstPendingTime = expirationTime;
} // Update the range of suspended times. Treat everything lower priority or
// equal to this update as unsuspended.
var firstSuspendedTime = root.firstSuspendedTime; // 首次为 0
if (firstSuspendedTime !== NoWork) { // 相等,不走这段逻辑
// 省略代码
}
}
performSyncWorkOnRoot
对 Root
执行任务。
该方法接收以下参数:
root
function performSyncWorkOnRoot(root) {
// Check if there's expired work on this root. Otherwise, render at Sync.
var lastExpiredTime = root.lastExpiredTime; // 0
var expirationTime = lastExpiredTime !== NoWork ? lastExpiredTime : Sync; // Sync
if (root.finishedExpirationTime === expirationTime) { // root.finishedExpirationTime 为 0
// 省略代码
} else {
// 省略代码
if (root !== workInProgressRoot || expirationTime !== renderExpirationTime) { // workInProgressRoot 为 null,renderExpirationTime 为 0
prepareFreshStack(root, expirationTime); // 准备阶段,将 root 赋值给 workInProgressRoot
startWorkOnPendingInteractions(root, expirationTime); // 首次渲染没做什么事
} // If we have a work-in-progress fiber, it means there's still work to do
// in this root.
if (workInProgress !== null) {
var prevExecutionContext = executionContext; // 8
executionContext |= RenderContext; // 24
var prevDispatcher = pushDispatcher(root);
var prevInteractions = pushInteractions(root);
startWorkLoopTimer(workInProgress);
do {
try {
workLoopSync(); // 终于到执行任务了!!
break;
} catch (thrownValue) {
handleError(root, thrownValue);
}
} while (true);
resetContextDependencies();
executionContext = prevExecutionContext;
popDispatcher(prevDispatcher);
if (enableSchedulerTracing) {
popInteractions(((prevInteractions: any): Set<Interaction>));
}
if (workInProgressRootExitStatus === RootFatalErrored) {
const fatalError = workInProgressRootFatalError;
stopInterruptedWorkLoopTimer();
prepareFreshStack(root, expirationTime);
markRootSuspendedAtTime(root, expirationTime);
ensureRootIsScheduled(root);
throw fatalError;
}
if (workInProgress !== null) {
// 省略代码
} else {
// We now have a consistent tree. Because this is a sync render, we
// will commit it even if something suspended.
stopFinishedWorkLoopTimer();
root.finishedWork = (root.current.alternate: any);
root.finishedExpirationTime = expirationTime;
finishSyncRender(root, workInProgressRootExitStatus, expirationTime);
}
// Before exiting, make sure there's a callback scheduled for the next
// pending level.
ensureRootIsScheduled(root);
}
}
prepareFreshStack
该方法接收以下参数:
root
expirationTime
function prepareFreshStack(root, expirationTime) {
root.finishedWork = null;
root.finishedExpirationTime = NoWork;
var timeoutHandle = root.timeoutHandle; // -1
// 省略代码
// 省略代码
workInProgressRoot = root;
workInProgress = createWorkInProgress(root.current, null, expirationTime);
renderExpirationTime = expirationTime;
workInProgressRootExitStatus = RootIncomplete; // 0
workInProgressRootFatalError = null;
workInProgressRootLatestProcessedExpirationTime = Sync;
workInProgressRootLatestSuspenseTimeout = Sync;
workInProgressRootCanSuspendUsingConfig = null;
workInProgressRootNextUnprocessedUpdateTime = NoWork; // 0
workInProgressRootHasPendingPing = false;
// 省略代码
}
createWorkInProgress
// This is used to create an alternate fiber to do work on.
export function createWorkInProgress(
current: Fiber,
pendingProps: any,
expirationTime: ExpirationTime,
): Fiber {
let workInProgress = current.alternate; // null
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, // 3
pendingProps, // null
current.key, // null
current.mode, // 8
);
workInProgress.elementType = current.elementType; // null
workInProgress.type = current.type; // null
workInProgress.stateNode = current.stateNode; // FiberRootNode 对象
// 省略代码
workInProgress.alternate = current; // FiberNode 对象
current.alternate = workInProgress;
} else {
// 省略代码
}
workInProgress.childExpirationTime = current.childExpirationTime; // 0
workInProgress.expirationTime = current.expirationTime;
workInProgress.child = current.child; // null
workInProgress.memoizedProps = current.memoizedProps; // null
workInProgress.memoizedState = current.memoizedState; // null
workInProgress.updateQueue = current.updateQueue;
// Clone the dependencies object. This is mutated during the render phase, so
// it cannot be shared with the current fiber.
const currentDependencies = current.dependencies; // null
workInProgress.dependencies =
currentDependencies === null
? null
: {
expirationTime: currentDependencies.expirationTime,
firstContext: currentDependencies.firstContext,
responders: currentDependencies.responders,
};
// These will be overridden during the parent's reconciliation
workInProgress.sibling = current.sibling; // null
workInProgress.index = current.index; // 0
workInProgress.ref = current.ref; // nullee
// 省略代码
// 省略dev环境代码
return workInProgress;
}
function startWorkLoopTimer(nextUnitOfWork: Fiber | null): void {
if (enableUserTimingAPI) { // true
currentFiber = nextUnitOfWork;
// 省略代码
}
}
workLoopSync
循环处理任务直到结束。
- 第一次处理
container
的Fiber
对象(HostRoot类型),处理完后将根组件从update
中取出并生成一个Fiber
对象(IndeterminateComponent类型)赋值给workInProgress
并处理;
function workLoopSync() {
// Already timed out, so perform work without checking if we need to yield.
while (workInProgress !== null) {
workInProgress = performUnitOfWork(workInProgress);
}
}
performUnitOfWork
该方法接收以下参数:
unitOfWork
,该参数是一个Fiber
对象
由此可见,work 的最小单位是一个 Fiber
对象。
function performUnitOfWork(unitOfWork: Fiber): Fiber | null {
// The current, flushed, state of this fiber is the alternate. Ideally
// nothing should rely on this, but relying on it here means that we don't
// need an additional field on the work in progress.
const current = unitOfWork.alternate;
startWorkTimer(unitOfWork);
setCurrentDebugFiberInDEV(unitOfWork); // 将 current 设置为 unitOfWork
let next;
if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) { // unitOfWork.mode = 8,PrifileMode = 8
startProfilerTimer(unitOfWork);
next = beginWork(current, unitOfWork, renderExpirationTime);
stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); // 与Profiler相关,暂且不管
} else {
// 省略代码
}
resetCurrentDebugFiberInDEV(); // 将 current 设置为 null
unitOfWork.memoizedProps = unitOfWork.pendingProps; // null
if (next === null) {
// If this doesn't spawn new work, complete the current work.
next = completeUnitOfWork(unitOfWork);
}
ReactCurrentOwner.current = null;
return next;
}