Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moved resetChildLanes into complete work #19836

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
202 changes: 197 additions & 5 deletions packages/react-reconciler/src/ReactFiberCompleteWork.new.js
Expand Up @@ -8,7 +8,7 @@
*/

import type {Fiber} from './ReactInternalTypes';
import type {Lanes} from './ReactFiberLane';
import type {Lanes, Lane} from './ReactFiberLane';
import type {
ReactFundamentalComponentInstance,
ReactScopeInstance,
Expand Down Expand Up @@ -58,14 +58,20 @@ import {
OffscreenComponent,
LegacyHiddenComponent,
} from './ReactWorkTags';
import {NoMode, BlockingMode, ProfileMode} from './ReactTypeOfMode';
import {
NoMode,
BlockingMode,
ConcurrentMode,
ProfileMode,
} from './ReactTypeOfMode';
import {
Ref,
Update,
NoFlags,
DidCapture,
Snapshot,
MutationMask,
StaticMask,
} from './ReactFiberFlags';
import invariant from 'shared/invariant';

Expand Down Expand Up @@ -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';
Expand Down Expand Up @@ -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,
Expand All @@ -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: {
Expand Down Expand Up @@ -720,6 +843,7 @@ function completeWork(
}
}
updateHostContainer(current, workInProgress);
bubbleProperties(workInProgress);
return null;
}
case HostComponent: {
Expand All @@ -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;
}

Expand Down Expand Up @@ -803,6 +928,7 @@ function completeWork(
markRef(workInProgress);
}
}
bubbleProperties(workInProgress);
return null;
}
case HostText: {
Expand Down Expand Up @@ -837,6 +963,7 @@ function completeWork(
);
}
}
bubbleProperties(workInProgress);
return null;
}
case SuspenseComponent: {
Expand All @@ -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.
Expand All @@ -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;
}
}
Expand All @@ -887,6 +1042,7 @@ function completeWork(
) {
transferActualDuration(workInProgress);
}
// Don't bubble properties in this case.
return workInProgress;
}

Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -984,6 +1155,7 @@ function completeWork(
if (isLegacyContextProvider(Component)) {
popLegacyContext(workInProgress);
}
bubbleProperties(workInProgress);
return null;
}
case SuspenseListComponent: {
Expand All @@ -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;
}

Expand Down Expand Up @@ -1060,6 +1233,7 @@ function completeWork(
ForceSuspenseFallback,
),
);
// Don't bubble properties in this case.
return workInProgress.child;
}
row = row.sibling;
Expand Down Expand Up @@ -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 (
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -1217,6 +1394,7 @@ function completeWork(
): any): Instance);
fundamentalInstance.instance = instance;
if (fundamentalImpl.reconcileChildren === false) {
bubbleProperties(workInProgress);
return null;
}
appendAllChildren(instance, workInProgress, false, false);
Expand All @@ -1239,6 +1417,7 @@ function completeWork(
markUpdate(workInProgress);
}
}
bubbleProperties(workInProgress);
return null;
}
break;
Expand All @@ -1261,31 +1440,44 @@ 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'
) {
workInProgress.flags |= Update;
}
}

// Don't bubble properties for hidden children.
if (
!nextIsHidden ||
includesSomeLane(subtreeRenderLanes, (OffscreenLane: Lane)) ||
(workInProgress.mode & ConcurrentMode) === NoMode
) {
bubbleProperties(workInProgress);
}

return null;
}
}
Expand Down