mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Moved resetChildLanes into complete work (#19836)
This allows us to inline a few checks that are specific to a certain tag-type.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
import type {Fiber} from './ReactInternalTypes';
|
||||
import type {Lanes} from './ReactFiberLane';
|
||||
import type {Lanes, Lane} from './ReactFiberLane';
|
||||
import type {
|
||||
ReactFundamentalComponentInstance,
|
||||
ReactScopeInstance,
|
||||
@@ -58,7 +58,12 @@ import {
|
||||
OffscreenComponent,
|
||||
LegacyHiddenComponent,
|
||||
} from './ReactWorkTags';
|
||||
import {NoMode, BlockingMode, ProfileMode} from './ReactTypeOfMode';
|
||||
import {
|
||||
NoMode,
|
||||
BlockingMode,
|
||||
ConcurrentMode,
|
||||
ProfileMode,
|
||||
} from './ReactTypeOfMode';
|
||||
import {
|
||||
Ref,
|
||||
Update,
|
||||
@@ -66,6 +71,7 @@ import {
|
||||
DidCapture,
|
||||
Snapshot,
|
||||
MutationMask,
|
||||
StaticMask,
|
||||
} from './ReactFiberFlags';
|
||||
import invariant from 'shared/invariant';
|
||||
|
||||
@@ -137,9 +143,16 @@ import {
|
||||
renderHasNotSuspendedYet,
|
||||
popRenderLanes,
|
||||
getRenderTargetTime,
|
||||
subtreeRenderLanes,
|
||||
} from './ReactFiberWorkLoop.new';
|
||||
import {createFundamentalStateInstance} from './ReactFiberFundamental.new';
|
||||
import {OffscreenLane, SomeRetryLane} from './ReactFiberLane';
|
||||
import {
|
||||
OffscreenLane,
|
||||
SomeRetryLane,
|
||||
NoLanes,
|
||||
includesSomeLane,
|
||||
mergeLanes,
|
||||
} from './ReactFiberLane';
|
||||
import {resetChildFibers} from './ReactChildFiber.new';
|
||||
import {createScopeInstance} from './ReactFiberScope.new';
|
||||
import {transferActualDuration} from './ReactProfilerTimer.new';
|
||||
@@ -668,6 +681,114 @@ function cutOffTailIfNeeded(
|
||||
}
|
||||
}
|
||||
|
||||
function bubbleProperties(completedWork: Fiber) {
|
||||
const didBailout =
|
||||
completedWork.alternate !== null &&
|
||||
completedWork.alternate.child === completedWork.child;
|
||||
|
||||
let newChildLanes = NoLanes;
|
||||
let subtreeFlags = NoFlags;
|
||||
|
||||
if (!didBailout) {
|
||||
// Bubble up the earliest expiration time.
|
||||
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
|
||||
// In profiling mode, resetChildExpirationTime is also used to reset
|
||||
// profiler durations.
|
||||
let actualDuration = completedWork.actualDuration;
|
||||
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
|
||||
|
||||
let child = completedWork.child;
|
||||
while (child !== null) {
|
||||
newChildLanes = mergeLanes(
|
||||
newChildLanes,
|
||||
mergeLanes(child.lanes, child.childLanes),
|
||||
);
|
||||
|
||||
subtreeFlags |= child.subtreeFlags;
|
||||
subtreeFlags |= child.flags;
|
||||
|
||||
// When a fiber is cloned, its actualDuration is reset to 0. This value will
|
||||
// only be updated if work is done on the fiber (i.e. it doesn't bailout).
|
||||
// When work is done, it should bubble to the parent's actualDuration. If
|
||||
// the fiber has not been cloned though, (meaning no work was done), then
|
||||
// this value will reflect the amount of time spent working on a previous
|
||||
// render. In that case it should not bubble. We determine whether it was
|
||||
// cloned by comparing the child pointer.
|
||||
actualDuration += child.actualDuration;
|
||||
|
||||
treeBaseDuration += child.treeBaseDuration;
|
||||
child = child.sibling;
|
||||
}
|
||||
|
||||
completedWork.actualDuration = actualDuration;
|
||||
completedWork.treeBaseDuration = treeBaseDuration;
|
||||
} else {
|
||||
let child = completedWork.child;
|
||||
while (child !== null) {
|
||||
newChildLanes = mergeLanes(
|
||||
newChildLanes,
|
||||
mergeLanes(child.lanes, child.childLanes),
|
||||
);
|
||||
|
||||
subtreeFlags |= child.subtreeFlags;
|
||||
subtreeFlags |= child.flags;
|
||||
|
||||
child = child.sibling;
|
||||
}
|
||||
}
|
||||
|
||||
completedWork.subtreeFlags |= subtreeFlags;
|
||||
} else {
|
||||
// Bubble up the earliest expiration time.
|
||||
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
|
||||
// In profiling mode, resetChildExpirationTime is also used to reset
|
||||
// profiler durations.
|
||||
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
|
||||
|
||||
let child = completedWork.child;
|
||||
while (child !== null) {
|
||||
newChildLanes = mergeLanes(
|
||||
newChildLanes,
|
||||
mergeLanes(child.lanes, child.childLanes),
|
||||
);
|
||||
|
||||
// "Static" flags share the lifetime of the fiber/hook they belong to,
|
||||
// so we should bubble those up even during a bailout. All the other
|
||||
// flags have a lifetime only of a single render + commit, so we should
|
||||
// ignore them.
|
||||
subtreeFlags |= child.subtreeFlags & StaticMask;
|
||||
subtreeFlags |= child.flags & StaticMask;
|
||||
|
||||
treeBaseDuration += child.treeBaseDuration;
|
||||
child = child.sibling;
|
||||
}
|
||||
|
||||
completedWork.treeBaseDuration = treeBaseDuration;
|
||||
} else {
|
||||
let child = completedWork.child;
|
||||
while (child !== null) {
|
||||
newChildLanes = mergeLanes(
|
||||
newChildLanes,
|
||||
mergeLanes(child.lanes, child.childLanes),
|
||||
);
|
||||
|
||||
// "Static" flags share the lifetime of the fiber/hook they belong to,
|
||||
// so we should bubble those up even during a bailout. All the other
|
||||
// flags have a lifetime only of a single render + commit, so we should
|
||||
// ignore them.
|
||||
subtreeFlags |= child.subtreeFlags & StaticMask;
|
||||
subtreeFlags |= child.flags & StaticMask;
|
||||
|
||||
child = child.sibling;
|
||||
}
|
||||
}
|
||||
|
||||
completedWork.subtreeFlags |= subtreeFlags;
|
||||
}
|
||||
|
||||
completedWork.childLanes = newChildLanes;
|
||||
}
|
||||
|
||||
function completeWork(
|
||||
current: Fiber | null,
|
||||
workInProgress: Fiber,
|
||||
@@ -686,12 +807,14 @@ function completeWork(
|
||||
case Profiler:
|
||||
case ContextConsumer:
|
||||
case MemoComponent:
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
case ClassComponent: {
|
||||
const Component = workInProgress.type;
|
||||
if (isLegacyContextProvider(Component)) {
|
||||
popLegacyContext(workInProgress);
|
||||
}
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
}
|
||||
case HostRoot: {
|
||||
@@ -720,6 +843,7 @@ function completeWork(
|
||||
}
|
||||
}
|
||||
updateHostContainer(current, workInProgress);
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
}
|
||||
case HostComponent: {
|
||||
@@ -746,6 +870,7 @@ function completeWork(
|
||||
'caused by a bug in React. Please file an issue.',
|
||||
);
|
||||
// This can happen when we abort work.
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -803,6 +928,7 @@ function completeWork(
|
||||
markRef(workInProgress);
|
||||
}
|
||||
}
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
}
|
||||
case HostText: {
|
||||
@@ -837,6 +963,7 @@ function completeWork(
|
||||
);
|
||||
}
|
||||
}
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
}
|
||||
case SuspenseComponent: {
|
||||
@@ -856,6 +983,20 @@ function completeWork(
|
||||
if (enableSchedulerTracing) {
|
||||
markSpawnedWork(OffscreenLane);
|
||||
}
|
||||
bubbleProperties(workInProgress);
|
||||
if (enableProfilerTimer) {
|
||||
if ((workInProgress.mode & ProfileMode) !== NoMode) {
|
||||
const isTimedOutSuspense = nextState !== null;
|
||||
if (isTimedOutSuspense) {
|
||||
// Don't count time spent in a timed out Suspense subtree as part of the base duration.
|
||||
const primaryChildFragment = workInProgress.child;
|
||||
if (primaryChildFragment !== null) {
|
||||
// $FlowFixMe Flow doens't support type casting in combiation with the -= operator
|
||||
workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
// We should never have been in a hydration state if we didn't have a current.
|
||||
@@ -872,6 +1013,20 @@ function completeWork(
|
||||
// If something suspended, schedule an effect to attach retry listeners.
|
||||
// So we might as well always mark this.
|
||||
workInProgress.flags |= Update;
|
||||
bubbleProperties(workInProgress);
|
||||
if (enableProfilerTimer) {
|
||||
if ((workInProgress.mode & ProfileMode) !== NoMode) {
|
||||
const isTimedOutSuspense = nextState !== null;
|
||||
if (isTimedOutSuspense) {
|
||||
// Don't count time spent in a timed out Suspense subtree as part of the base duration.
|
||||
const primaryChildFragment = workInProgress.child;
|
||||
if (primaryChildFragment !== null) {
|
||||
// $FlowFixMe Flow doens't support type casting in combiation with the -= operator
|
||||
workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -887,6 +1042,7 @@ function completeWork(
|
||||
) {
|
||||
transferActualDuration(workInProgress);
|
||||
}
|
||||
// Don't bubble properties in this case.
|
||||
return workInProgress;
|
||||
}
|
||||
|
||||
@@ -964,6 +1120,19 @@ function completeWork(
|
||||
// Always notify the callback
|
||||
workInProgress.flags |= Update;
|
||||
}
|
||||
bubbleProperties(workInProgress);
|
||||
if (enableProfilerTimer) {
|
||||
if ((workInProgress.mode & ProfileMode) !== NoMode) {
|
||||
if (nextDidTimeout) {
|
||||
// Don't count time spent in a timed out Suspense subtree as part of the base duration.
|
||||
const primaryChildFragment = workInProgress.child;
|
||||
if (primaryChildFragment !== null) {
|
||||
// $FlowFixMe Flow doens't support type casting in combiation with the -= operator
|
||||
workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
case HostPortal:
|
||||
@@ -972,10 +1141,12 @@ function completeWork(
|
||||
if (current === null) {
|
||||
preparePortalMount(workInProgress.stateNode.containerInfo);
|
||||
}
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
case ContextProvider:
|
||||
// Pop provider fiber
|
||||
popProvider(workInProgress);
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
case IncompleteClassComponent: {
|
||||
// Same as class component case. I put it down here so that the tags are
|
||||
@@ -984,6 +1155,7 @@ function completeWork(
|
||||
if (isLegacyContextProvider(Component)) {
|
||||
popLegacyContext(workInProgress);
|
||||
}
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
}
|
||||
case SuspenseListComponent: {
|
||||
@@ -995,6 +1167,7 @@ function completeWork(
|
||||
if (renderState === null) {
|
||||
// We're running in the default, "independent" mode.
|
||||
// We don't do anything in this mode.
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1060,6 +1233,7 @@ function completeWork(
|
||||
ForceSuspenseFallback,
|
||||
),
|
||||
);
|
||||
// Don't bubble properties in this case.
|
||||
return workInProgress.child;
|
||||
}
|
||||
row = row.sibling;
|
||||
@@ -1117,6 +1291,7 @@ function completeWork(
|
||||
!getIsHydrating() // We don't cut it if we're hydrating.
|
||||
) {
|
||||
// We're done.
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
}
|
||||
} else if (
|
||||
@@ -1188,8 +1363,10 @@ function completeWork(
|
||||
}
|
||||
pushSuspenseContext(workInProgress, suspenseContext);
|
||||
// Do a pass over the next row.
|
||||
// Don't bubble properties in this case.
|
||||
return next;
|
||||
}
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
}
|
||||
case FundamentalComponent: {
|
||||
@@ -1217,6 +1394,7 @@ function completeWork(
|
||||
): any): Instance);
|
||||
fundamentalInstance.instance = instance;
|
||||
if (fundamentalImpl.reconcileChildren === false) {
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
}
|
||||
appendAllChildren(instance, workInProgress, false, false);
|
||||
@@ -1239,6 +1417,7 @@ function completeWork(
|
||||
markUpdate(workInProgress);
|
||||
}
|
||||
}
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
@@ -1261,24 +1440,27 @@ function completeWork(
|
||||
markRef(workInProgress);
|
||||
}
|
||||
}
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Block:
|
||||
if (enableBlocksAPI) {
|
||||
bubbleProperties(workInProgress);
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
case OffscreenComponent:
|
||||
case LegacyHiddenComponent: {
|
||||
popRenderLanes(workInProgress);
|
||||
const nextState: OffscreenState | null = workInProgress.memoizedState;
|
||||
const nextIsHidden = nextState !== null;
|
||||
|
||||
if (current !== null) {
|
||||
const nextState: OffscreenState | null = workInProgress.memoizedState;
|
||||
const prevState: OffscreenState | null = current.memoizedState;
|
||||
|
||||
const prevIsHidden = prevState !== null;
|
||||
const nextIsHidden = nextState !== null;
|
||||
if (
|
||||
prevIsHidden !== nextIsHidden &&
|
||||
newProps.mode !== 'unstable-defer-without-hiding'
|
||||
@@ -1286,6 +1468,16 @@ function completeWork(
|
||||
workInProgress.flags |= Update;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't bubble properties for hidden children.
|
||||
if (
|
||||
!nextIsHidden ||
|
||||
includesSomeLane(subtreeRenderLanes, (OffscreenLane: Lane)) ||
|
||||
(workInProgress.mode & ConcurrentMode) === NoMode
|
||||
) {
|
||||
bubbleProperties(workInProgress);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,8 +115,6 @@ import {
|
||||
MemoComponent,
|
||||
SimpleMemoComponent,
|
||||
Block,
|
||||
OffscreenComponent,
|
||||
LegacyHiddenComponent,
|
||||
ScopeComponent,
|
||||
} from './ReactWorkTags';
|
||||
import {LegacyRoot} from './ReactRootTags';
|
||||
@@ -139,7 +137,6 @@ import {
|
||||
MutationMask,
|
||||
LayoutMask,
|
||||
PassiveMask,
|
||||
StaticMask,
|
||||
} from './ReactFiberFlags';
|
||||
import {
|
||||
NoLanePriority,
|
||||
@@ -151,7 +148,6 @@ import {
|
||||
NoLane,
|
||||
SyncLane,
|
||||
SyncBatchedLane,
|
||||
OffscreenLane,
|
||||
NoTimestamp,
|
||||
findUpdateLane,
|
||||
findTransitionLane,
|
||||
@@ -290,7 +286,7 @@ let workInProgressRootRenderLanes: Lanes = NoLanes;
|
||||
//
|
||||
// Most things in the work loop should deal with workInProgressRootRenderLanes.
|
||||
// Most things in begin/complete phases should deal with subtreeRenderLanes.
|
||||
let subtreeRenderLanes: Lanes = NoLanes;
|
||||
export let subtreeRenderLanes: Lanes = NoLanes;
|
||||
const subtreeRenderLanesCursor: StackCursor<Lanes> = createCursor(NoLanes);
|
||||
|
||||
// Whether to root completed, errored, suspended, etc.
|
||||
@@ -1719,8 +1715,6 @@ function completeUnitOfWork(unitOfWork: Fiber): void {
|
||||
workInProgress = next;
|
||||
return;
|
||||
}
|
||||
|
||||
resetChildLanes(completedWork);
|
||||
} else {
|
||||
// This fiber did not complete because something threw. Pop values off
|
||||
// the stack without entering the complete phase. If this is a boundary,
|
||||
@@ -1782,150 +1776,6 @@ function completeUnitOfWork(unitOfWork: Fiber): void {
|
||||
}
|
||||
}
|
||||
|
||||
function resetChildLanes(completedWork: Fiber) {
|
||||
if (
|
||||
// TODO: Move this check out of the hot path by moving `resetChildLanes`
|
||||
// to switch statement in `completeWork`.
|
||||
(completedWork.tag === LegacyHiddenComponent ||
|
||||
completedWork.tag === OffscreenComponent) &&
|
||||
completedWork.memoizedState !== null &&
|
||||
!includesSomeLane(subtreeRenderLanes, (OffscreenLane: Lane)) &&
|
||||
(completedWork.mode & ConcurrentMode) !== NoLanes
|
||||
) {
|
||||
// The children of this component are hidden. Don't bubble their
|
||||
// expiration times.
|
||||
return;
|
||||
}
|
||||
|
||||
const didBailout =
|
||||
completedWork.alternate !== null &&
|
||||
completedWork.alternate.child === completedWork.child;
|
||||
|
||||
let newChildLanes = NoLanes;
|
||||
let subtreeFlags = NoFlags;
|
||||
|
||||
if (!didBailout) {
|
||||
// Bubble up the earliest expiration time.
|
||||
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
|
||||
// In profiling mode, resetChildExpirationTime is also used to reset
|
||||
// profiler durations.
|
||||
let actualDuration = completedWork.actualDuration;
|
||||
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
|
||||
|
||||
let child = completedWork.child;
|
||||
while (child !== null) {
|
||||
newChildLanes = mergeLanes(
|
||||
newChildLanes,
|
||||
mergeLanes(child.lanes, child.childLanes),
|
||||
);
|
||||
|
||||
subtreeFlags |= child.subtreeFlags;
|
||||
subtreeFlags |= child.flags;
|
||||
|
||||
// When a fiber is cloned, its actualDuration is reset to 0. This value will
|
||||
// only be updated if work is done on the fiber (i.e. it doesn't bailout).
|
||||
// When work is done, it should bubble to the parent's actualDuration. If
|
||||
// the fiber has not been cloned though, (meaning no work was done), then
|
||||
// this value will reflect the amount of time spent working on a previous
|
||||
// render. In that case it should not bubble. We determine whether it was
|
||||
// cloned by comparing the child pointer.
|
||||
actualDuration += child.actualDuration;
|
||||
|
||||
treeBaseDuration += child.treeBaseDuration;
|
||||
child = child.sibling;
|
||||
}
|
||||
|
||||
const isTimedOutSuspense =
|
||||
completedWork.tag === SuspenseComponent &&
|
||||
completedWork.memoizedState !== null;
|
||||
if (isTimedOutSuspense) {
|
||||
// Don't count time spent in a timed out Suspense subtree as part of the base duration.
|
||||
const primaryChildFragment = completedWork.child;
|
||||
if (primaryChildFragment !== null) {
|
||||
treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
|
||||
}
|
||||
}
|
||||
|
||||
completedWork.actualDuration = actualDuration;
|
||||
completedWork.treeBaseDuration = treeBaseDuration;
|
||||
} else {
|
||||
let child = completedWork.child;
|
||||
while (child !== null) {
|
||||
newChildLanes = mergeLanes(
|
||||
newChildLanes,
|
||||
mergeLanes(child.lanes, child.childLanes),
|
||||
);
|
||||
|
||||
subtreeFlags |= child.subtreeFlags;
|
||||
subtreeFlags |= child.flags;
|
||||
|
||||
child = child.sibling;
|
||||
}
|
||||
}
|
||||
|
||||
completedWork.subtreeFlags |= subtreeFlags;
|
||||
} else {
|
||||
// Bubble up the earliest expiration time.
|
||||
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
|
||||
// In profiling mode, resetChildExpirationTime is also used to reset
|
||||
// profiler durations.
|
||||
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
|
||||
|
||||
let child = completedWork.child;
|
||||
while (child !== null) {
|
||||
newChildLanes = mergeLanes(
|
||||
newChildLanes,
|
||||
mergeLanes(child.lanes, child.childLanes),
|
||||
);
|
||||
|
||||
// "Static" flags share the lifetime of the fiber/hook they belong to,
|
||||
// so we should bubble those up even during a bailout. All the other
|
||||
// flags have a lifetime only of a single render + commit, so we should
|
||||
// ignore them.
|
||||
subtreeFlags |= child.subtreeFlags & StaticMask;
|
||||
subtreeFlags |= child.flags & StaticMask;
|
||||
|
||||
treeBaseDuration += child.treeBaseDuration;
|
||||
child = child.sibling;
|
||||
}
|
||||
|
||||
const isTimedOutSuspense =
|
||||
completedWork.tag === SuspenseComponent &&
|
||||
completedWork.memoizedState !== null;
|
||||
if (isTimedOutSuspense) {
|
||||
// Don't count time spent in a timed out Suspense subtree as part of the base duration.
|
||||
const primaryChildFragment = completedWork.child;
|
||||
if (primaryChildFragment !== null) {
|
||||
treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
|
||||
}
|
||||
}
|
||||
|
||||
completedWork.treeBaseDuration = treeBaseDuration;
|
||||
} else {
|
||||
let child = completedWork.child;
|
||||
while (child !== null) {
|
||||
newChildLanes = mergeLanes(
|
||||
newChildLanes,
|
||||
mergeLanes(child.lanes, child.childLanes),
|
||||
);
|
||||
|
||||
// "Static" flags share the lifetime of the fiber/hook they belong to,
|
||||
// so we should bubble those up even during a bailout. All the other
|
||||
// flags have a lifetime only of a single render + commit, so we should
|
||||
// ignore them.
|
||||
subtreeFlags |= child.subtreeFlags & StaticMask;
|
||||
subtreeFlags |= child.flags & StaticMask;
|
||||
|
||||
child = child.sibling;
|
||||
}
|
||||
}
|
||||
|
||||
completedWork.subtreeFlags |= subtreeFlags;
|
||||
}
|
||||
|
||||
completedWork.childLanes = newChildLanes;
|
||||
}
|
||||
|
||||
function commitRoot(root) {
|
||||
const renderPriorityLevel = getCurrentPriorityLevel();
|
||||
runWithPriority(
|
||||
|
||||
Reference in New Issue
Block a user