Skip to content

Commit 44174cd

Browse files
author
Brian Vaughn
committed
Offscreen: Use JS stack to track hidden/unhidden subtree state
1 parent ee6a05c commit 44174cd

File tree

2 files changed

+112
-70
lines changed

2 files changed

+112
-70
lines changed

packages/react-reconciler/src/ReactFiberCommitWork.new.js

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,6 @@ if (__DEV__) {
152152
didWarnAboutUndefinedSnapshotBeforeUpdate = new Set();
153153
}
154154

155-
// Used during the commit phase to track the state of the Offscreen component stack.
156-
// Allows us to avoid traversing the return path to find the nearest Offscreen ancestor.
157-
// Only used when enableSuspenseLayoutEffectSemantics is enabled.
158-
let offscreenSubtreeIsHidden: boolean = false;
159-
const offscreenSubtreeIsHiddenStack: Array<boolean> = [];
160-
let offscreenSubtreeWasHidden: boolean = false;
161-
const offscreenSubtreeWasHiddenStack: Array<boolean> = [];
162-
163155
const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set;
164156

165157
let nextEffect: Fiber | null = null;
@@ -2283,13 +2275,38 @@ export function commitLayoutEffects(
22832275
committedLanes: Lanes,
22842276
): void {
22852277
nextEffect = finishedWork;
2286-
commitLayoutEffects_begin(finishedWork, root, committedLanes);
2278+
commitLayoutEffects_intermediate(
2279+
finishedWork,
2280+
root,
2281+
committedLanes,
2282+
false,
2283+
false,
2284+
);
2285+
}
2286+
2287+
export function commitLayoutEffects_intermediate(
2288+
finishedWork: Fiber,
2289+
root: FiberRoot,
2290+
committedLanes: Lanes,
2291+
subtreeWasHidden: boolean,
2292+
subtreeIsHidden: boolean,
2293+
): void {
2294+
nextEffect = finishedWork;
2295+
commitLayoutEffects_begin(
2296+
finishedWork,
2297+
root,
2298+
committedLanes,
2299+
subtreeWasHidden,
2300+
subtreeIsHidden,
2301+
);
22872302
}
22882303

22892304
function commitLayoutEffects_begin(
22902305
subtreeRoot: Fiber,
22912306
root: FiberRoot,
22922307
committedLanes: Lanes,
2308+
subtreeWasHidden: boolean,
2309+
subtreeIsHidden: boolean,
22932310
) {
22942311
// Suspense layout effects semantics don't change for legacy roots.
22952312
const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;
@@ -2305,11 +2322,25 @@ function commitLayoutEffects_begin(
23052322
const wasHidden = current !== null && current.memoizedState !== null;
23062323
const isHidden = fiber.memoizedState !== null;
23072324

2308-
offscreenSubtreeWasHidden = wasHidden || offscreenSubtreeWasHidden;
2309-
offscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden;
2325+
const newOffscreenSubtreeWasHidden = wasHidden || subtreeWasHidden;
2326+
const newOffscreenSubtreeIsHidden = isHidden || subtreeIsHidden;
23102327

2311-
offscreenSubtreeWasHiddenStack.push(wasHidden);
2312-
offscreenSubtreeIsHiddenStack.push(isHidden);
2328+
if (
2329+
newOffscreenSubtreeWasHidden !== subtreeWasHidden ||
2330+
newOffscreenSubtreeIsHidden !== subtreeIsHidden
2331+
) {
2332+
// Traverse the Offscreen subtree with the current Offscreen as the root.
2333+
nextEffect = fiber.child;
2334+
commitLayoutEffects_intermediate(
2335+
fiber, // New root; bubble back up to here and stop.
2336+
root,
2337+
committedLanes,
2338+
newOffscreenSubtreeWasHidden,
2339+
newOffscreenSubtreeIsHidden,
2340+
);
2341+
nextEffect = fiber.sibling;
2342+
continue;
2343+
}
23132344
}
23142345
}
23152346

@@ -2318,8 +2349,7 @@ function commitLayoutEffects_begin(
23182349
nextEffect = firstChild;
23192350
} else {
23202351
if (enableSuspenseLayoutEffectSemantics && isModernRoot) {
2321-
const visibilityChanged =
2322-
!offscreenSubtreeIsHidden && offscreenSubtreeWasHidden;
2352+
const visibilityChanged = !subtreeIsHidden && subtreeWasHidden;
23232353
if (
23242354
visibilityChanged &&
23252355
(fiber.subtreeFlags & LayoutStatic) !== NoFlags &&
@@ -2334,7 +2364,13 @@ function commitLayoutEffects_begin(
23342364
}
23352365
}
23362366

2337-
commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);
2367+
commitLayoutMountEffects_complete(
2368+
subtreeRoot,
2369+
root,
2370+
committedLanes,
2371+
subtreeWasHidden,
2372+
subtreeIsHidden,
2373+
);
23382374
}
23392375
}
23402376
}
@@ -2343,35 +2379,20 @@ function commitLayoutMountEffects_complete(
23432379
subtreeRoot: Fiber,
23442380
root: FiberRoot,
23452381
committedLanes: Lanes,
2382+
subtreeWasHidden: boolean,
2383+
subtreeIsHidden: boolean,
23462384
) {
23472385
// Suspense layout effects semantics don't change for legacy roots.
23482386
const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;
23492387

23502388
while (nextEffect !== null) {
23512389
const fiber = nextEffect;
23522390

2353-
if (enableSuspenseLayoutEffectSemantics && isModernRoot) {
2354-
if (fiber.tag === OffscreenComponent) {
2355-
offscreenSubtreeWasHiddenStack.pop();
2356-
offscreenSubtreeIsHiddenStack.pop();
2357-
offscreenSubtreeWasHidden =
2358-
offscreenSubtreeWasHiddenStack.length > 0 &&
2359-
offscreenSubtreeWasHiddenStack[
2360-
offscreenSubtreeWasHiddenStack.length - 1
2361-
];
2362-
offscreenSubtreeIsHidden =
2363-
offscreenSubtreeIsHiddenStack.length > 0 &&
2364-
offscreenSubtreeIsHiddenStack[
2365-
offscreenSubtreeIsHiddenStack.length - 1
2366-
];
2367-
}
2368-
}
2369-
23702391
if (
23712392
enableSuspenseLayoutEffectSemantics &&
23722393
isModernRoot &&
2373-
offscreenSubtreeWasHidden &&
2374-
!offscreenSubtreeIsHidden
2394+
subtreeWasHidden &&
2395+
!subtreeIsHidden
23752396
) {
23762397
// Inside of an Offscreen subtree that changed visibility during this commit.
23772398
// If this subtree was hidden, layout effects will have already been destroyed (during mutation phase)

packages/react-reconciler/src/ReactFiberCommitWork.old.js

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,6 @@ if (__DEV__) {
152152
didWarnAboutUndefinedSnapshotBeforeUpdate = new Set();
153153
}
154154

155-
// Used during the commit phase to track the state of the Offscreen component stack.
156-
// Allows us to avoid traversing the return path to find the nearest Offscreen ancestor.
157-
// Only used when enableSuspenseLayoutEffectSemantics is enabled.
158-
let offscreenSubtreeIsHidden: boolean = false;
159-
const offscreenSubtreeIsHiddenStack: Array<boolean> = [];
160-
let offscreenSubtreeWasHidden: boolean = false;
161-
const offscreenSubtreeWasHiddenStack: Array<boolean> = [];
162-
163155
const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set;
164156

165157
let nextEffect: Fiber | null = null;
@@ -2283,13 +2275,38 @@ export function commitLayoutEffects(
22832275
committedLanes: Lanes,
22842276
): void {
22852277
nextEffect = finishedWork;
2286-
commitLayoutEffects_begin(finishedWork, root, committedLanes);
2278+
commitLayoutEffects_intermediate(
2279+
finishedWork,
2280+
root,
2281+
committedLanes,
2282+
false,
2283+
false,
2284+
);
2285+
}
2286+
2287+
export function commitLayoutEffects_intermediate(
2288+
finishedWork: Fiber,
2289+
root: FiberRoot,
2290+
committedLanes: Lanes,
2291+
subtreeWasHidden: boolean,
2292+
subtreeIsHidden: boolean,
2293+
): void {
2294+
nextEffect = finishedWork;
2295+
commitLayoutEffects_begin(
2296+
finishedWork,
2297+
root,
2298+
committedLanes,
2299+
subtreeWasHidden,
2300+
subtreeIsHidden,
2301+
);
22872302
}
22882303

22892304
function commitLayoutEffects_begin(
22902305
subtreeRoot: Fiber,
22912306
root: FiberRoot,
22922307
committedLanes: Lanes,
2308+
subtreeWasHidden: boolean,
2309+
subtreeIsHidden: boolean,
22932310
) {
22942311
// Suspense layout effects semantics don't change for legacy roots.
22952312
const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;
@@ -2305,11 +2322,25 @@ function commitLayoutEffects_begin(
23052322
const wasHidden = current !== null && current.memoizedState !== null;
23062323
const isHidden = fiber.memoizedState !== null;
23072324

2308-
offscreenSubtreeWasHidden = wasHidden || offscreenSubtreeWasHidden;
2309-
offscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden;
2325+
const newOffscreenSubtreeWasHidden = wasHidden || subtreeWasHidden;
2326+
const newOffscreenSubtreeIsHidden = isHidden || subtreeIsHidden;
23102327

2311-
offscreenSubtreeWasHiddenStack.push(wasHidden);
2312-
offscreenSubtreeIsHiddenStack.push(isHidden);
2328+
if (
2329+
newOffscreenSubtreeWasHidden !== subtreeWasHidden ||
2330+
newOffscreenSubtreeIsHidden !== subtreeIsHidden
2331+
) {
2332+
// Traverse the Offscreen subtree with the current Offscreen as the root.
2333+
nextEffect = fiber.child;
2334+
commitLayoutEffects_intermediate(
2335+
fiber, // New root; bubble back up to here and stop.
2336+
root,
2337+
committedLanes,
2338+
newOffscreenSubtreeWasHidden,
2339+
newOffscreenSubtreeIsHidden,
2340+
);
2341+
nextEffect = fiber.sibling;
2342+
continue;
2343+
}
23132344
}
23142345
}
23152346

@@ -2318,8 +2349,7 @@ function commitLayoutEffects_begin(
23182349
nextEffect = firstChild;
23192350
} else {
23202351
if (enableSuspenseLayoutEffectSemantics && isModernRoot) {
2321-
const visibilityChanged =
2322-
!offscreenSubtreeIsHidden && offscreenSubtreeWasHidden;
2352+
const visibilityChanged = !subtreeIsHidden && subtreeWasHidden;
23232353
if (
23242354
visibilityChanged &&
23252355
(fiber.subtreeFlags & LayoutStatic) !== NoFlags &&
@@ -2334,7 +2364,13 @@ function commitLayoutEffects_begin(
23342364
}
23352365
}
23362366

2337-
commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);
2367+
commitLayoutMountEffects_complete(
2368+
subtreeRoot,
2369+
root,
2370+
committedLanes,
2371+
subtreeWasHidden,
2372+
subtreeIsHidden,
2373+
);
23382374
}
23392375
}
23402376
}
@@ -2343,35 +2379,20 @@ function commitLayoutMountEffects_complete(
23432379
subtreeRoot: Fiber,
23442380
root: FiberRoot,
23452381
committedLanes: Lanes,
2382+
subtreeWasHidden: boolean,
2383+
subtreeIsHidden: boolean,
23462384
) {
23472385
// Suspense layout effects semantics don't change for legacy roots.
23482386
const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;
23492387

23502388
while (nextEffect !== null) {
23512389
const fiber = nextEffect;
23522390

2353-
if (enableSuspenseLayoutEffectSemantics && isModernRoot) {
2354-
if (fiber.tag === OffscreenComponent) {
2355-
offscreenSubtreeWasHiddenStack.pop();
2356-
offscreenSubtreeIsHiddenStack.pop();
2357-
offscreenSubtreeWasHidden =
2358-
offscreenSubtreeWasHiddenStack.length > 0 &&
2359-
offscreenSubtreeWasHiddenStack[
2360-
offscreenSubtreeWasHiddenStack.length - 1
2361-
];
2362-
offscreenSubtreeIsHidden =
2363-
offscreenSubtreeIsHiddenStack.length > 0 &&
2364-
offscreenSubtreeIsHiddenStack[
2365-
offscreenSubtreeIsHiddenStack.length - 1
2366-
];
2367-
}
2368-
}
2369-
23702391
if (
23712392
enableSuspenseLayoutEffectSemantics &&
23722393
isModernRoot &&
2373-
offscreenSubtreeWasHidden &&
2374-
!offscreenSubtreeIsHidden
2394+
subtreeWasHidden &&
2395+
!subtreeIsHidden
23752396
) {
23762397
// Inside of an Offscreen subtree that changed visibility during this commit.
23772398
// If this subtree was hidden, layout effects will have already been destroyed (during mutation phase)

0 commit comments

Comments
 (0)