From b93998301a81f3c349147971b083f2c3456099cf Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Wed, 7 Apr 2021 17:14:10 -0400 Subject: [PATCH] Offscreen: Use JS stack to track hidden/unhidden subtree state --- .../src/ReactFiberCommitWork.new.js | 86 ++++++++++++------- .../src/ReactFiberCommitWork.old.js | 86 ++++++++++++------- 2 files changed, 110 insertions(+), 62 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index 48150f021a32b..f563bb141d882 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -152,14 +152,6 @@ if (__DEV__) { didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); } -// Used during the commit phase to track the state of the Offscreen component stack. -// Allows us to avoid traversing the return path to find the nearest Offscreen ancestor. -// Only used when enableSuspenseLayoutEffectSemantics is enabled. -let offscreenSubtreeIsHidden: boolean = false; -const offscreenSubtreeIsHiddenStack: Array = []; -let offscreenSubtreeWasHidden: boolean = false; -const offscreenSubtreeWasHiddenStack: Array = []; - const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set; let nextEffect: Fiber | null = null; @@ -2283,13 +2275,38 @@ export function commitLayoutEffects( committedLanes: Lanes, ): void { nextEffect = finishedWork; - commitLayoutEffects_begin(finishedWork, root, committedLanes); + commitLayoutEffects_intermediate( + finishedWork, + root, + committedLanes, + false, + false, + ); +} + +export function commitLayoutEffects_intermediate( + finishedWork: Fiber, + root: FiberRoot, + committedLanes: Lanes, + offscreenSubtreeWasHidden: boolean, + offscreenSubtreeIsHidden: boolean, +): void { + nextEffect = finishedWork; + commitLayoutEffects_begin( + finishedWork, + root, + committedLanes, + offscreenSubtreeWasHidden, + offscreenSubtreeIsHidden, + ); } function commitLayoutEffects_begin( subtreeRoot: Fiber, root: FiberRoot, committedLanes: Lanes, + offscreenSubtreeWasHidden: boolean, + offscreenSubtreeIsHidden: boolean, ) { // Suspense layout effects semantics don't change for legacy roots. const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode; @@ -2305,11 +2322,27 @@ function commitLayoutEffects_begin( const wasHidden = current !== null && current.memoizedState !== null; const isHidden = fiber.memoizedState !== null; - offscreenSubtreeWasHidden = wasHidden || offscreenSubtreeWasHidden; - offscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden; + const newOffscreenSubtreeWasHidden = + wasHidden || offscreenSubtreeWasHidden; + const newOffscreenSubtreeIsHidden = + isHidden || offscreenSubtreeIsHidden; - offscreenSubtreeWasHiddenStack.push(wasHidden); - offscreenSubtreeIsHiddenStack.push(isHidden); + if ( + newOffscreenSubtreeWasHidden !== offscreenSubtreeWasHidden || + newOffscreenSubtreeIsHidden !== offscreenSubtreeIsHidden + ) { + // Traverse the Offscreen subtree with the current Offscreen as the root. + nextEffect = fiber.child; + commitLayoutEffects_intermediate( + fiber, // New root; bubble back up to here and stop. + root, + committedLanes, + newOffscreenSubtreeWasHidden, + newOffscreenSubtreeIsHidden, + ); + nextEffect = fiber.sibling; + continue; + } } } @@ -2334,7 +2367,13 @@ function commitLayoutEffects_begin( } } - commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes); + commitLayoutMountEffects_complete( + subtreeRoot, + root, + committedLanes, + offscreenSubtreeWasHidden, + offscreenSubtreeIsHidden, + ); } } } @@ -2343,6 +2382,8 @@ function commitLayoutMountEffects_complete( subtreeRoot: Fiber, root: FiberRoot, committedLanes: Lanes, + offscreenSubtreeWasHidden: boolean, + offscreenSubtreeIsHidden: boolean, ) { // Suspense layout effects semantics don't change for legacy roots. const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode; @@ -2350,23 +2391,6 @@ function commitLayoutMountEffects_complete( while (nextEffect !== null) { const fiber = nextEffect; - if (enableSuspenseLayoutEffectSemantics && isModernRoot) { - if (fiber.tag === OffscreenComponent) { - offscreenSubtreeWasHiddenStack.pop(); - offscreenSubtreeIsHiddenStack.pop(); - offscreenSubtreeWasHidden = - offscreenSubtreeWasHiddenStack.length > 0 && - offscreenSubtreeWasHiddenStack[ - offscreenSubtreeWasHiddenStack.length - 1 - ]; - offscreenSubtreeIsHidden = - offscreenSubtreeIsHiddenStack.length > 0 && - offscreenSubtreeIsHiddenStack[ - offscreenSubtreeIsHiddenStack.length - 1 - ]; - } - } - if ( enableSuspenseLayoutEffectSemantics && isModernRoot && diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.old.js b/packages/react-reconciler/src/ReactFiberCommitWork.old.js index ca3dbe363f071..af764eab78a83 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.old.js @@ -152,14 +152,6 @@ if (__DEV__) { didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); } -// Used during the commit phase to track the state of the Offscreen component stack. -// Allows us to avoid traversing the return path to find the nearest Offscreen ancestor. -// Only used when enableSuspenseLayoutEffectSemantics is enabled. -let offscreenSubtreeIsHidden: boolean = false; -const offscreenSubtreeIsHiddenStack: Array = []; -let offscreenSubtreeWasHidden: boolean = false; -const offscreenSubtreeWasHiddenStack: Array = []; - const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set; let nextEffect: Fiber | null = null; @@ -2283,13 +2275,38 @@ export function commitLayoutEffects( committedLanes: Lanes, ): void { nextEffect = finishedWork; - commitLayoutEffects_begin(finishedWork, root, committedLanes); + commitLayoutEffects_intermediate( + finishedWork, + root, + committedLanes, + false, + false, + ); +} + +export function commitLayoutEffects_intermediate( + finishedWork: Fiber, + root: FiberRoot, + committedLanes: Lanes, + offscreenSubtreeWasHidden: boolean, + offscreenSubtreeIsHidden: boolean, +): void { + nextEffect = finishedWork; + commitLayoutEffects_begin( + finishedWork, + root, + committedLanes, + offscreenSubtreeWasHidden, + offscreenSubtreeIsHidden, + ); } function commitLayoutEffects_begin( subtreeRoot: Fiber, root: FiberRoot, committedLanes: Lanes, + offscreenSubtreeWasHidden: boolean, + offscreenSubtreeIsHidden: boolean, ) { // Suspense layout effects semantics don't change for legacy roots. const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode; @@ -2305,11 +2322,27 @@ function commitLayoutEffects_begin( const wasHidden = current !== null && current.memoizedState !== null; const isHidden = fiber.memoizedState !== null; - offscreenSubtreeWasHidden = wasHidden || offscreenSubtreeWasHidden; - offscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden; + const newOffscreenSubtreeWasHidden = + wasHidden || offscreenSubtreeWasHidden; + const newOffscreenSubtreeIsHidden = + isHidden || offscreenSubtreeIsHidden; - offscreenSubtreeWasHiddenStack.push(wasHidden); - offscreenSubtreeIsHiddenStack.push(isHidden); + if ( + newOffscreenSubtreeWasHidden !== offscreenSubtreeWasHidden || + newOffscreenSubtreeIsHidden !== offscreenSubtreeIsHidden + ) { + // Traverse the Offscreen subtree with the current Offscreen as the root. + nextEffect = fiber.child; + commitLayoutEffects_intermediate( + fiber, // New root; bubble back up to here and stop. + root, + committedLanes, + newOffscreenSubtreeWasHidden, + newOffscreenSubtreeIsHidden, + ); + nextEffect = fiber.sibling; + continue; + } } } @@ -2334,7 +2367,13 @@ function commitLayoutEffects_begin( } } - commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes); + commitLayoutMountEffects_complete( + subtreeRoot, + root, + committedLanes, + offscreenSubtreeWasHidden, + offscreenSubtreeIsHidden, + ); } } } @@ -2343,6 +2382,8 @@ function commitLayoutMountEffects_complete( subtreeRoot: Fiber, root: FiberRoot, committedLanes: Lanes, + offscreenSubtreeWasHidden: boolean, + offscreenSubtreeIsHidden: boolean, ) { // Suspense layout effects semantics don't change for legacy roots. const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode; @@ -2350,23 +2391,6 @@ function commitLayoutMountEffects_complete( while (nextEffect !== null) { const fiber = nextEffect; - if (enableSuspenseLayoutEffectSemantics && isModernRoot) { - if (fiber.tag === OffscreenComponent) { - offscreenSubtreeWasHiddenStack.pop(); - offscreenSubtreeIsHiddenStack.pop(); - offscreenSubtreeWasHidden = - offscreenSubtreeWasHiddenStack.length > 0 && - offscreenSubtreeWasHiddenStack[ - offscreenSubtreeWasHiddenStack.length - 1 - ]; - offscreenSubtreeIsHidden = - offscreenSubtreeIsHiddenStack.length > 0 && - offscreenSubtreeIsHiddenStack[ - offscreenSubtreeIsHiddenStack.length - 1 - ]; - } - } - if ( enableSuspenseLayoutEffectSemantics && isModernRoot &&