Skip to content

Commit 00f5aa5

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

File tree

2 files changed

+76
-70
lines changed

2 files changed

+76
-70
lines changed

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

Lines changed: 38 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,21 @@ export function commitLayoutEffects(
22832275
committedLanes: Lanes,
22842276
): void {
22852277
nextEffect = finishedWork;
2286-
commitLayoutEffects_begin(finishedWork, root, committedLanes);
2278+
commitLayoutEffects_begin(
2279+
finishedWork,
2280+
root,
2281+
committedLanes,
2282+
false,
2283+
false,
2284+
);
22872285
}
22882286

22892287
function commitLayoutEffects_begin(
22902288
subtreeRoot: Fiber,
22912289
root: FiberRoot,
22922290
committedLanes: Lanes,
2291+
subtreeWasHidden: boolean,
2292+
subtreeIsHidden: boolean,
22932293
) {
22942294
// Suspense layout effects semantics don't change for legacy roots.
22952295
const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;
@@ -2305,11 +2305,24 @@ function commitLayoutEffects_begin(
23052305
const wasHidden = current !== null && current.memoizedState !== null;
23062306
const isHidden = fiber.memoizedState !== null;
23072307

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

2311-
offscreenSubtreeWasHiddenStack.push(wasHidden);
2312-
offscreenSubtreeIsHiddenStack.push(isHidden);
2311+
if (
2312+
newOffscreenSubtreeWasHidden !== subtreeWasHidden ||
2313+
newOffscreenSubtreeIsHidden !== subtreeIsHidden
2314+
) {
2315+
// Traverse the Offscreen subtree with the current Offscreen as the root.
2316+
commitLayoutEffects_begin(
2317+
fiber, // New root; bubble back up to here and stop.
2318+
root,
2319+
committedLanes,
2320+
newOffscreenSubtreeWasHidden,
2321+
newOffscreenSubtreeIsHidden,
2322+
);
2323+
nextEffect = fiber.sibling;
2324+
continue;
2325+
}
23132326
}
23142327
}
23152328

@@ -2318,8 +2331,7 @@ function commitLayoutEffects_begin(
23182331
nextEffect = firstChild;
23192332
} else {
23202333
if (enableSuspenseLayoutEffectSemantics && isModernRoot) {
2321-
const visibilityChanged =
2322-
!offscreenSubtreeIsHidden && offscreenSubtreeWasHidden;
2334+
const visibilityChanged = !subtreeIsHidden && subtreeWasHidden;
23232335
if (
23242336
visibilityChanged &&
23252337
(fiber.subtreeFlags & LayoutStatic) !== NoFlags &&
@@ -2334,7 +2346,13 @@ function commitLayoutEffects_begin(
23342346
}
23352347
}
23362348

2337-
commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);
2349+
commitLayoutMountEffects_complete(
2350+
subtreeRoot,
2351+
root,
2352+
committedLanes,
2353+
subtreeWasHidden,
2354+
subtreeIsHidden,
2355+
);
23382356
}
23392357
}
23402358
}
@@ -2343,35 +2361,20 @@ function commitLayoutMountEffects_complete(
23432361
subtreeRoot: Fiber,
23442362
root: FiberRoot,
23452363
committedLanes: Lanes,
2364+
subtreeWasHidden: boolean,
2365+
subtreeIsHidden: boolean,
23462366
) {
23472367
// Suspense layout effects semantics don't change for legacy roots.
23482368
const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;
23492369

23502370
while (nextEffect !== null) {
23512371
const fiber = nextEffect;
23522372

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-
23702373
if (
23712374
enableSuspenseLayoutEffectSemantics &&
23722375
isModernRoot &&
2373-
offscreenSubtreeWasHidden &&
2374-
!offscreenSubtreeIsHidden
2376+
subtreeWasHidden &&
2377+
!subtreeIsHidden
23752378
) {
23762379
// Inside of an Offscreen subtree that changed visibility during this commit.
23772380
// If this subtree was hidden, layout effects will have already been destroyed (during mutation phase)

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

Lines changed: 38 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,21 @@ export function commitLayoutEffects(
22832275
committedLanes: Lanes,
22842276
): void {
22852277
nextEffect = finishedWork;
2286-
commitLayoutEffects_begin(finishedWork, root, committedLanes);
2278+
commitLayoutEffects_begin(
2279+
finishedWork,
2280+
root,
2281+
committedLanes,
2282+
false,
2283+
false,
2284+
);
22872285
}
22882286

22892287
function commitLayoutEffects_begin(
22902288
subtreeRoot: Fiber,
22912289
root: FiberRoot,
22922290
committedLanes: Lanes,
2291+
subtreeWasHidden: boolean,
2292+
subtreeIsHidden: boolean,
22932293
) {
22942294
// Suspense layout effects semantics don't change for legacy roots.
22952295
const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;
@@ -2305,11 +2305,24 @@ function commitLayoutEffects_begin(
23052305
const wasHidden = current !== null && current.memoizedState !== null;
23062306
const isHidden = fiber.memoizedState !== null;
23072307

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

2311-
offscreenSubtreeWasHiddenStack.push(wasHidden);
2312-
offscreenSubtreeIsHiddenStack.push(isHidden);
2311+
if (
2312+
newOffscreenSubtreeWasHidden !== subtreeWasHidden ||
2313+
newOffscreenSubtreeIsHidden !== subtreeIsHidden
2314+
) {
2315+
// Traverse the Offscreen subtree with the current Offscreen as the root.
2316+
commitLayoutEffects_begin(
2317+
fiber, // New root; bubble back up to here and stop.
2318+
root,
2319+
committedLanes,
2320+
newOffscreenSubtreeWasHidden,
2321+
newOffscreenSubtreeIsHidden,
2322+
);
2323+
nextEffect = fiber.sibling;
2324+
continue;
2325+
}
23132326
}
23142327
}
23152328

@@ -2318,8 +2331,7 @@ function commitLayoutEffects_begin(
23182331
nextEffect = firstChild;
23192332
} else {
23202333
if (enableSuspenseLayoutEffectSemantics && isModernRoot) {
2321-
const visibilityChanged =
2322-
!offscreenSubtreeIsHidden && offscreenSubtreeWasHidden;
2334+
const visibilityChanged = !subtreeIsHidden && subtreeWasHidden;
23232335
if (
23242336
visibilityChanged &&
23252337
(fiber.subtreeFlags & LayoutStatic) !== NoFlags &&
@@ -2334,7 +2346,13 @@ function commitLayoutEffects_begin(
23342346
}
23352347
}
23362348

2337-
commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);
2349+
commitLayoutMountEffects_complete(
2350+
subtreeRoot,
2351+
root,
2352+
committedLanes,
2353+
subtreeWasHidden,
2354+
subtreeIsHidden,
2355+
);
23382356
}
23392357
}
23402358
}
@@ -2343,35 +2361,20 @@ function commitLayoutMountEffects_complete(
23432361
subtreeRoot: Fiber,
23442362
root: FiberRoot,
23452363
committedLanes: Lanes,
2364+
subtreeWasHidden: boolean,
2365+
subtreeIsHidden: boolean,
23462366
) {
23472367
// Suspense layout effects semantics don't change for legacy roots.
23482368
const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;
23492369

23502370
while (nextEffect !== null) {
23512371
const fiber = nextEffect;
23522372

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-
23702373
if (
23712374
enableSuspenseLayoutEffectSemantics &&
23722375
isModernRoot &&
2373-
offscreenSubtreeWasHidden &&
2374-
!offscreenSubtreeIsHidden
2376+
subtreeWasHidden &&
2377+
!subtreeIsHidden
23752378
) {
23762379
// Inside of an Offscreen subtree that changed visibility during this commit.
23772380
// If this subtree was hidden, layout effects will have already been destroyed (during mutation phase)

0 commit comments

Comments
 (0)