From fe81e362489bbaed90db385dabcc700fe5f02ca1 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Wed, 7 Apr 2021 17:45:19 -0400 Subject: [PATCH] Offscreen: Use JS stack to track hidden/unhidden subtree state (#21192) --- .../src/ReactFiberCommitWork.new.js | 51 ++++++++++--------- .../src/ReactFiberCommitWork.old.js | 51 ++++++++++--------- 2 files changed, 56 insertions(+), 46 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index 48150f021a32b..5f3870ac95f32 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -156,9 +156,7 @@ if (__DEV__) { // 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; @@ -2305,11 +2303,35 @@ function commitLayoutEffects_begin( const wasHidden = current !== null && current.memoizedState !== null; const isHidden = fiber.memoizedState !== null; - offscreenSubtreeWasHidden = wasHidden || offscreenSubtreeWasHidden; - offscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden; + const newOffscreenSubtreeIsHidden = + isHidden || offscreenSubtreeIsHidden; + const newOffscreenSubtreeWasHidden = + wasHidden || offscreenSubtreeWasHidden; - offscreenSubtreeWasHiddenStack.push(wasHidden); - offscreenSubtreeIsHiddenStack.push(isHidden); + if ( + newOffscreenSubtreeIsHidden !== offscreenSubtreeIsHidden || + newOffscreenSubtreeWasHidden !== offscreenSubtreeWasHidden + ) { + const prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden; + const prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; + + nextEffect = fiber; + offscreenSubtreeIsHidden = newOffscreenSubtreeIsHidden; + offscreenSubtreeWasHidden = newOffscreenSubtreeWasHidden; + + // Traverse the Offscreen subtree with the current Offscreen as the root. + commitLayoutEffects_begin( + fiber, // New root; bubble back up to here and stop. + root, + committedLanes, + ); + + nextEffect = fiber.sibling; + offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; + offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; + + continue; + } } } @@ -2350,23 +2372,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..10fa7d1c206f3 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.old.js @@ -156,9 +156,7 @@ if (__DEV__) { // 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; @@ -2305,11 +2303,35 @@ function commitLayoutEffects_begin( const wasHidden = current !== null && current.memoizedState !== null; const isHidden = fiber.memoizedState !== null; - offscreenSubtreeWasHidden = wasHidden || offscreenSubtreeWasHidden; - offscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden; + const newOffscreenSubtreeIsHidden = + isHidden || offscreenSubtreeIsHidden; + const newOffscreenSubtreeWasHidden = + wasHidden || offscreenSubtreeWasHidden; - offscreenSubtreeWasHiddenStack.push(wasHidden); - offscreenSubtreeIsHiddenStack.push(isHidden); + if ( + newOffscreenSubtreeIsHidden !== offscreenSubtreeIsHidden || + newOffscreenSubtreeWasHidden !== offscreenSubtreeWasHidden + ) { + const prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden; + const prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; + + nextEffect = fiber; + offscreenSubtreeIsHidden = newOffscreenSubtreeIsHidden; + offscreenSubtreeWasHidden = newOffscreenSubtreeWasHidden; + + // Traverse the Offscreen subtree with the current Offscreen as the root. + commitLayoutEffects_begin( + fiber, // New root; bubble back up to here and stop. + root, + committedLanes, + ); + + nextEffect = fiber.sibling; + offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; + offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; + + continue; + } } } @@ -2350,23 +2372,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 &&