Skip to content

Commit b939983

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

File tree

2 files changed

+110
-62
lines changed

2 files changed

+110
-62
lines changed

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

Lines changed: 55 additions & 31 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+
offscreenSubtreeWasHidden: boolean,
2292+
offscreenSubtreeIsHidden: boolean,
2293+
): void {
2294+
nextEffect = finishedWork;
2295+
commitLayoutEffects_begin(
2296+
finishedWork,
2297+
root,
2298+
committedLanes,
2299+
offscreenSubtreeWasHidden,
2300+
offscreenSubtreeIsHidden,
2301+
);
22872302
}
22882303

22892304
function commitLayoutEffects_begin(
22902305
subtreeRoot: Fiber,
22912306
root: FiberRoot,
22922307
committedLanes: Lanes,
2308+
offscreenSubtreeWasHidden: boolean,
2309+
offscreenSubtreeIsHidden: boolean,
22932310
) {
22942311
// Suspense layout effects semantics don't change for legacy roots.
22952312
const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;
@@ -2305,11 +2322,27 @@ 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 =
2326+
wasHidden || offscreenSubtreeWasHidden;
2327+
const newOffscreenSubtreeIsHidden =
2328+
isHidden || offscreenSubtreeIsHidden;
23102329

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

@@ -2334,7 +2367,13 @@ function commitLayoutEffects_begin(
23342367
}
23352368
}
23362369

2337-
commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);
2370+
commitLayoutMountEffects_complete(
2371+
subtreeRoot,
2372+
root,
2373+
committedLanes,
2374+
offscreenSubtreeWasHidden,
2375+
offscreenSubtreeIsHidden,
2376+
);
23382377
}
23392378
}
23402379
}
@@ -2343,30 +2382,15 @@ function commitLayoutMountEffects_complete(
23432382
subtreeRoot: Fiber,
23442383
root: FiberRoot,
23452384
committedLanes: Lanes,
2385+
offscreenSubtreeWasHidden: boolean,
2386+
offscreenSubtreeIsHidden: boolean,
23462387
) {
23472388
// Suspense layout effects semantics don't change for legacy roots.
23482389
const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;
23492390

23502391
while (nextEffect !== null) {
23512392
const fiber = nextEffect;
23522393

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-
23702394
if (
23712395
enableSuspenseLayoutEffectSemantics &&
23722396
isModernRoot &&

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

Lines changed: 55 additions & 31 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+
offscreenSubtreeWasHidden: boolean,
2292+
offscreenSubtreeIsHidden: boolean,
2293+
): void {
2294+
nextEffect = finishedWork;
2295+
commitLayoutEffects_begin(
2296+
finishedWork,
2297+
root,
2298+
committedLanes,
2299+
offscreenSubtreeWasHidden,
2300+
offscreenSubtreeIsHidden,
2301+
);
22872302
}
22882303

22892304
function commitLayoutEffects_begin(
22902305
subtreeRoot: Fiber,
22912306
root: FiberRoot,
22922307
committedLanes: Lanes,
2308+
offscreenSubtreeWasHidden: boolean,
2309+
offscreenSubtreeIsHidden: boolean,
22932310
) {
22942311
// Suspense layout effects semantics don't change for legacy roots.
22952312
const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;
@@ -2305,11 +2322,27 @@ 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 =
2326+
wasHidden || offscreenSubtreeWasHidden;
2327+
const newOffscreenSubtreeIsHidden =
2328+
isHidden || offscreenSubtreeIsHidden;
23102329

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

@@ -2334,7 +2367,13 @@ function commitLayoutEffects_begin(
23342367
}
23352368
}
23362369

2337-
commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);
2370+
commitLayoutMountEffects_complete(
2371+
subtreeRoot,
2372+
root,
2373+
committedLanes,
2374+
offscreenSubtreeWasHidden,
2375+
offscreenSubtreeIsHidden,
2376+
);
23382377
}
23392378
}
23402379
}
@@ -2343,30 +2382,15 @@ function commitLayoutMountEffects_complete(
23432382
subtreeRoot: Fiber,
23442383
root: FiberRoot,
23452384
committedLanes: Lanes,
2385+
offscreenSubtreeWasHidden: boolean,
2386+
offscreenSubtreeIsHidden: boolean,
23462387
) {
23472388
// Suspense layout effects semantics don't change for legacy roots.
23482389
const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;
23492390

23502391
while (nextEffect !== null) {
23512392
const fiber = nextEffect;
23522393

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-
23702394
if (
23712395
enableSuspenseLayoutEffectSemantics &&
23722396
isModernRoot &&

0 commit comments

Comments
 (0)