Skip to content

Commit

Permalink
[internal] add activity mode for legacy hidden
Browse files Browse the repository at this point in the history
  • Loading branch information
rickhanlonii committed Mar 3, 2025
1 parent b045f18 commit 54fdb2f
Show file tree
Hide file tree
Showing 21 changed files with 259 additions and 29 deletions.
9 changes: 9 additions & 0 deletions packages/react-reconciler/src/ReactFiberActivityComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,12 @@ export function isOffscreenManual(offscreenFiber: Fiber): boolean {
offscreenFiber.memoizedProps.mode === 'manual'
);
}

export function isLegacyHiddenMode(fiber: Fiber): boolean {
return (
fiber != null &&
fiber.memoizedProps != null &&
(fiber.memoizedProps.mode === 'unstable-legacy-hidden' ||
fiber.memoizedProps.mode === 'unstable-defer-without-hiding')
);
}
3 changes: 3 additions & 0 deletions packages/react-reconciler/src/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ import {
callComponentInDEV,
callRenderInDEV,
} from './ReactFiberCallUserSpace';
import {enableReplaceLegacyHiddenWithActivity} from 'shared/ReactFeatureFlags';

// A special exception that's used to unwind the stack when an update flows
// into a dehydrated boundary.
Expand Down Expand Up @@ -659,6 +660,8 @@ function updateOffscreenComponent(
nextProps.mode === 'hidden' ||
(enableLegacyHidden &&
nextProps.mode === 'unstable-defer-without-hiding') ||
(enableReplaceLegacyHiddenWithActivity &&
nextProps.mode === 'unstable-legacy-hidden') ||
nextIsDetached
) {
// Rendering a hidden tree.
Expand Down
156 changes: 144 additions & 12 deletions packages/react-reconciler/src/ReactFiberCommitWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ import type {SuspenseState, RetryQueue} from './ReactFiberSuspenseComponent';
import type {UpdateQueue} from './ReactFiberClassUpdateQueue';
import type {FunctionComponentUpdateQueue} from './ReactFiberHooks';
import type {Wakeable} from 'shared/ReactTypes';
import {isOffscreenManual} from './ReactFiberActivityComponent';
import {
isLegacyHiddenMode,
isOffscreenManual,
} from './ReactFiberActivityComponent';
import type {
OffscreenState,
OffscreenInstance,
Expand Down Expand Up @@ -61,6 +64,7 @@ import {
disableLegacyMode,
enableComponentPerformanceTrack,
enableViewTransition,
enableReplaceLegacyHiddenWithActivity,
} from 'shared/ReactFeatureFlags';
import {
FunctionComponent,
Expand Down Expand Up @@ -700,6 +704,18 @@ function commitLayoutEffectOnFiber(
break;
}
case OffscreenComponent: {
if (
enableReplaceLegacyHiddenWithActivity &&
(isLegacyHiddenMode(finishedWork) || isLegacyHiddenMode(current))
) {
recursivelyTraverseLayoutEffects(
finishedRoot,
finishedWork,
committedLanes,
);
break;
}

const isModernRoot =
disableLegacyMode || (finishedWork.mode & ConcurrentMode) !== NoMode;
if (isModernRoot) {
Expand Down Expand Up @@ -1534,6 +1550,17 @@ function commitDeletionEffectsOnFiber(
return;
}
case OffscreenComponent: {
if (
enableReplaceLegacyHiddenWithActivity &&
isLegacyHiddenMode(deletedFiber)
) {
recursivelyTraverseDeletionEffects(
finishedRoot,
nearestMountedAncestor,
deletedFiber,
);
break;
}
if (!offscreenSubtreeWasHidden) {
safelyDetachRef(deletedFiber, nearestMountedAncestor);
}
Expand Down Expand Up @@ -1643,13 +1670,20 @@ function getRetryCache(finishedWork: Fiber) {
return retryCache;
}
case OffscreenComponent: {
const instance: OffscreenInstance = finishedWork.stateNode;
let retryCache: null | Set<Wakeable> | WeakSet<Wakeable> =
instance._retryCache;
if (retryCache === null) {
retryCache = instance._retryCache = new PossiblyWeakSet();
if (
enableReplaceLegacyHiddenWithActivity &&
isLegacyHiddenMode(finishedWork)
) {
// Fall through to error
} else {
const instance: OffscreenInstance = finishedWork.stateNode;
let retryCache: null | Set<Wakeable> | WeakSet<Wakeable> =
instance._retryCache;
if (retryCache === null) {
retryCache = instance._retryCache = new PossiblyWeakSet();
}
return retryCache;
}
return retryCache;
}
default: {
throw new Error(
Expand Down Expand Up @@ -2168,6 +2202,14 @@ function commitMutationEffectsOnFiber(
break;
}
case OffscreenComponent: {
if (
enableReplaceLegacyHiddenWithActivity &&
(isLegacyHiddenMode(finishedWork) || isLegacyHiddenMode(current))
) {
recursivelyTraverseMutationEffects(root, finishedWork, lanes);
commitReconciliationEffects(finishedWork, lanes);
break;
}
if (flags & Ref) {
if (!offscreenSubtreeWasHidden && current !== null) {
safelyDetachRef(current, current.return);
Expand Down Expand Up @@ -2473,6 +2515,13 @@ function commitAfterMutationEffectsOnFiber(
break;
}
case OffscreenComponent: {
if (
enableReplaceLegacyHiddenWithActivity &&
(isLegacyHiddenMode(finishedWork) || isLegacyHiddenMode(current))
) {
recursivelyTraverseAfterMutationEffects(root, finishedWork, lanes);
break;
}
const isModernRoot =
disableLegacyMode || (finishedWork.mode & ConcurrentMode) !== NoMode;
if (isModernRoot) {
Expand Down Expand Up @@ -2645,6 +2694,14 @@ export function disappearLayoutEffects(finishedWork: Fiber) {
break;
}
case OffscreenComponent: {
if (
enableReplaceLegacyHiddenWithActivity &&
isLegacyHiddenMode(finishedWork)
) {
recursivelyTraverseDisappearLayoutEffects(finishedWork);
break;
}

// TODO (Offscreen) Check: flags & RefStatic
safelyDetachRef(finishedWork, finishedWork.return);

Expand Down Expand Up @@ -2835,6 +2892,17 @@ export function reappearLayoutEffects(
break;
}
case OffscreenComponent: {
if (
enableReplaceLegacyHiddenWithActivity &&
isLegacyHiddenMode(finishedWork)
) {
recursivelyTraverseReappearLayoutEffects(
finishedRoot,
finishedWork,
includeWorkInProgressEffects,
);
break;
}
const offscreenState: OffscreenState = finishedWork.memoizedState;
const isHidden = offscreenState !== null;
if (isHidden) {
Expand Down Expand Up @@ -3463,6 +3531,27 @@ function commitPassiveMountOnFiber(
break;
}
case OffscreenComponent: {
if (
enableReplaceLegacyHiddenWithActivity &&
(isLegacyHiddenMode(finishedWork) ||
isLegacyHiddenMode(finishedWork.alternate))
) {
recursivelyTraversePassiveMountEffects(
finishedRoot,
finishedWork,
committedLanes,
committedTransitions,
endTime,
);

if (flags & Passive) {
const current = finishedWork.alternate;
const instance: OffscreenInstance = finishedWork.stateNode;
commitOffscreenPassiveMountEffects(current, finishedWork, instance);
}
break;
}

// TODO: Pass `current` as argument to this function
const instance: OffscreenInstance = finishedWork.stateNode;
const current = finishedWork.alternate;
Expand Down Expand Up @@ -3780,6 +3869,21 @@ export function reconnectPassiveEffects(
break;
}
case OffscreenComponent: {
if (
(enableReplaceLegacyHiddenWithActivity &&
isLegacyHiddenMode(finishedWork)) ||
isLegacyHiddenMode(finishedWork.alternate)
) {
recursivelyTraverseReconnectPassiveEffects(
finishedRoot,
finishedWork,
committedLanes,
committedTransitions,
includeWorkInProgressEffects,
endTime,
);
break;
}
const instance: OffscreenInstance = finishedWork.stateNode;
const nextState: OffscreenState | null = finishedWork.memoizedState;

Expand Down Expand Up @@ -3995,11 +4099,16 @@ function commitAtomicPassiveEffects(
committedTransitions,
endTime,
);
if (flags & Passive) {
// TODO: Pass `current` as argument to this function
const current = finishedWork.alternate;
const instance: OffscreenInstance = finishedWork.stateNode;
commitOffscreenPassiveMountEffects(current, finishedWork, instance);
// TODO: Pass `current` as argument to this function
const current = finishedWork.alternate;
if (
!enableReplaceLegacyHiddenWithActivity ||
(!isLegacyHiddenMode(finishedWork) && !isLegacyHiddenMode(current))
) {
if (flags & Passive) {
const instance: OffscreenInstance = finishedWork.stateNode;
commitOffscreenPassiveMountEffects(current, finishedWork, instance);
}
}
break;
}
Expand Down Expand Up @@ -4110,6 +4219,13 @@ function accumulateSuspenseyCommitOnFiber(fiber: Fiber) {
break;
}
case OffscreenComponent: {
if (
enableReplaceLegacyHiddenWithActivity &&
(isLegacyHiddenMode(fiber) || isLegacyHiddenMode(fiber.alternate))
) {
recursivelyAccumulateSuspenseyCommit(fiber);
break;
}
const isHidden = (fiber.memoizedState: OffscreenState | null) !== null;
if (isHidden) {
// Don't suspend in hidden trees
Expand Down Expand Up @@ -4257,6 +4373,14 @@ function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {
break;
}
case OffscreenComponent: {
if (
(enableReplaceLegacyHiddenWithActivity &&
isLegacyHiddenMode(finishedWork)) ||
isLegacyHiddenMode(finishedWork.alternate)
) {
recursivelyTraversePassiveUnmountEffects(finishedWork);
break;
}
const instance: OffscreenInstance = finishedWork.stateNode;
const nextState: OffscreenState | null = finishedWork.memoizedState;

Expand Down Expand Up @@ -4355,6 +4479,14 @@ export function disconnectPassiveEffect(finishedWork: Fiber): void {
break;
}
case OffscreenComponent: {
if (
enableReplaceLegacyHiddenWithActivity &&
(isLegacyHiddenMode(finishedWork) ||
isLegacyHiddenMode(finishedWork.alternate))
) {
recursivelyTraverseDisconnectPassiveEffects(finishedWork);
break;
}
const instance: OffscreenInstance = finishedWork.stateNode;
if (instance._visibility & OffscreenPassiveEffectsConnected) {
instance._visibility &= ~OffscreenPassiveEffectsConnected;
Expand Down
39 changes: 30 additions & 9 deletions packages/react-reconciler/src/ReactFiberCompleteWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ import type {
OffscreenState,
OffscreenQueue,
} from './ReactFiberActivityComponent';
import {isOffscreenManual} from './ReactFiberActivityComponent';
import {
isLegacyHiddenMode,
isOffscreenManual,
} from './ReactFiberActivityComponent';
import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent';
import type {Cache} from './ReactFiberCacheComponent';
import {
Expand Down Expand Up @@ -180,6 +183,7 @@ import {
popRootMarkerInstance,
} from './ReactFiberTracingMarkerComponent';
import {suspendCommit} from './ReactFiberThenable';
import {enableReplaceLegacyHiddenWithActivity} from 'shared/forks/ReactFeatureFlags.native-fb-dynamic';

/**
* Tag the fiber with an update effect. This turns a Placement into
Expand Down Expand Up @@ -299,7 +303,8 @@ function appendAllChildren(
// the portal directly.
} else if (
node.tag === OffscreenComponent &&
node.memoizedState !== null
node.memoizedState !== null &&
!isLegacyHiddenMode(node)
) {
// The children in this boundary are hidden. Toggle their visibility
// before appending.
Expand Down Expand Up @@ -371,7 +376,8 @@ function appendAllChildrenToContainer(
// the portal directly.
} else if (
node.tag === OffscreenComponent &&
node.memoizedState !== null
node.memoizedState !== null &&
!isLegacyHiddenMode(node)
) {
// The children in this boundary are hidden. Toggle their visibility
// before appending.
Expand Down Expand Up @@ -619,7 +625,8 @@ function scheduleRetryEffect(
// TODO: This check should probably be moved into claimNextRetryLane
// I also suspect that we need some further consolidation of offscreen
// and retry lanes.
workInProgress.tag !== OffscreenComponent
workInProgress.tag !== OffscreenComponent ||
isLegacyHiddenMode(workInProgress)
? claimNextRetryLane()
: OffscreenLane;
workInProgress.lanes = mergeLanes(workInProgress.lanes, retryLane);
Expand Down Expand Up @@ -1755,10 +1762,18 @@ function completeWork(
const nextState: OffscreenState | null = workInProgress.memoizedState;
const nextIsHidden = nextState !== null;

// Schedule a Visibility effect if the visibility has changed
if (enableLegacyHidden && workInProgress.tag === LegacyHiddenComponent) {
if (
enableReplaceLegacyHiddenWithActivity &&
isLegacyHiddenMode(workInProgress)
) {
// LegacyHidden doesn't do any hiding — it only pre-renders.
} else if (
enableLegacyHidden &&
workInProgress.tag === LegacyHiddenComponent
) {
// LegacyHidden doesn't do any hiding — it only pre-renders.
} else {
// Schedule a Visibility effect if the visibility has changed
if (current !== null) {
const prevState: OffscreenState | null = current.memoizedState;
const prevIsHidden = prevState !== null;
Expand Down Expand Up @@ -1793,10 +1808,16 @@ function completeWork(
// If so, we need to hide those nodes in the commit phase, so
// schedule a visibility effect.
if (
(!enableLegacyHidden ||
workInProgress.tag !== LegacyHiddenComponent) &&
workInProgress.subtreeFlags & (Placement | Update)
enableLegacyHidden &&
workInProgress.tag === LegacyHiddenComponent
) {
// LegacyHidden doesn't do any hiding — it only pre-renders.
} else if (
enableReplaceLegacyHiddenWithActivity &&
isLegacyHiddenMode(workInProgress)
) {
// LegacyHidden doesn't do any hiding — it only pre-renders.
} else if (workInProgress.subtreeFlags & (Placement | Update)) {
workInProgress.flags |= Visibility;
}
}
Expand Down
Loading

0 comments on commit 54fdb2f

Please sign in to comment.