From 99eef9e2df7b6aade461a1a958eb3838239e72c4 Mon Sep 17 00:00:00 2001 From: Ricky Date: Tue, 3 May 2022 10:16:53 -0400 Subject: [PATCH] Hide children of Offscreen after destroy effects (#24446) --- .../src/ReactFiberCommitWork.new.js | 67 +++++++++++++------ .../src/ReactFiberCommitWork.old.js | 67 +++++++++++++------ packages/shared/ReactFeatureFlags.js | 1 + .../forks/ReactFeatureFlags.native-fb.js | 1 + .../forks/ReactFeatureFlags.native-oss.js | 1 + .../forks/ReactFeatureFlags.test-renderer.js | 1 + .../ReactFeatureFlags.test-renderer.native.js | 1 + .../ReactFeatureFlags.test-renderer.www.js | 1 + .../shared/forks/ReactFeatureFlags.testing.js | 1 + .../forks/ReactFeatureFlags.testing.www.js | 1 + .../forks/ReactFeatureFlags.www-dynamic.js | 1 + .../shared/forks/ReactFeatureFlags.www.js | 1 + 12 files changed, 106 insertions(+), 38 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index 6712e27bd28e1..0c89aba8cdbdd 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -42,6 +42,7 @@ import { enableUpdaterTracking, enableCache, enableTransitionTracing, + enableFlipOffscreenUnhideOrder, } from 'shared/ReactFeatureFlags'; import { FunctionComponent, @@ -2270,28 +2271,56 @@ function commitMutationEffectsOnFiber( const isHidden = newState !== null; const offscreenBoundary: Fiber = finishedWork; - if (supportsMutation) { - // TODO: This needs to run whenever there's an insertion or update - // inside a hidden Offscreen tree. - hideOrUnhideAllChildren(offscreenBoundary, isHidden); - } - - if (enableSuspenseLayoutEffectSemantics) { - if (isHidden) { - if (!wasHidden) { - if ((offscreenBoundary.mode & ConcurrentMode) !== NoMode) { - nextEffect = offscreenBoundary; - let offscreenChild = offscreenBoundary.child; - while (offscreenChild !== null) { - nextEffect = offscreenChild; - disappearLayoutEffects_begin(offscreenChild); - offscreenChild = offscreenChild.sibling; + if (enableFlipOffscreenUnhideOrder) { + if (enableSuspenseLayoutEffectSemantics) { + if (isHidden) { + if (!wasHidden) { + if ((offscreenBoundary.mode & ConcurrentMode) !== NoMode) { + nextEffect = offscreenBoundary; + let offscreenChild = offscreenBoundary.child; + while (offscreenChild !== null) { + nextEffect = offscreenChild; + disappearLayoutEffects_begin(offscreenChild); + offscreenChild = offscreenChild.sibling; + } } } + } else { + if (wasHidden) { + // TODO: Move re-appear call here for symmetry? + } } - } else { - if (wasHidden) { - // TODO: Move re-appear call here for symmetry? + } + + if (supportsMutation) { + // TODO: This needs to run whenever there's an insertion or update + // inside a hidden Offscreen tree. + hideOrUnhideAllChildren(offscreenBoundary, isHidden); + } + } else { + if (supportsMutation) { + // TODO: This needs to run whenever there's an insertion or update + // inside a hidden Offscreen tree. + hideOrUnhideAllChildren(offscreenBoundary, isHidden); + } + + if (enableSuspenseLayoutEffectSemantics) { + if (isHidden) { + if (!wasHidden) { + if ((offscreenBoundary.mode & ConcurrentMode) !== NoMode) { + nextEffect = offscreenBoundary; + let offscreenChild = offscreenBoundary.child; + while (offscreenChild !== null) { + nextEffect = offscreenChild; + disappearLayoutEffects_begin(offscreenChild); + offscreenChild = offscreenChild.sibling; + } + } + } + } else { + if (wasHidden) { + // TODO: Move re-appear call here for symmetry? + } } } } diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.old.js b/packages/react-reconciler/src/ReactFiberCommitWork.old.js index a00355b6f5fc8..0cd78fdc13a3e 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.old.js @@ -42,6 +42,7 @@ import { enableUpdaterTracking, enableCache, enableTransitionTracing, + enableFlipOffscreenUnhideOrder, } from 'shared/ReactFeatureFlags'; import { FunctionComponent, @@ -2270,28 +2271,56 @@ function commitMutationEffectsOnFiber( const isHidden = newState !== null; const offscreenBoundary: Fiber = finishedWork; - if (supportsMutation) { - // TODO: This needs to run whenever there's an insertion or update - // inside a hidden Offscreen tree. - hideOrUnhideAllChildren(offscreenBoundary, isHidden); - } - - if (enableSuspenseLayoutEffectSemantics) { - if (isHidden) { - if (!wasHidden) { - if ((offscreenBoundary.mode & ConcurrentMode) !== NoMode) { - nextEffect = offscreenBoundary; - let offscreenChild = offscreenBoundary.child; - while (offscreenChild !== null) { - nextEffect = offscreenChild; - disappearLayoutEffects_begin(offscreenChild); - offscreenChild = offscreenChild.sibling; + if (enableFlipOffscreenUnhideOrder) { + if (enableSuspenseLayoutEffectSemantics) { + if (isHidden) { + if (!wasHidden) { + if ((offscreenBoundary.mode & ConcurrentMode) !== NoMode) { + nextEffect = offscreenBoundary; + let offscreenChild = offscreenBoundary.child; + while (offscreenChild !== null) { + nextEffect = offscreenChild; + disappearLayoutEffects_begin(offscreenChild); + offscreenChild = offscreenChild.sibling; + } } } + } else { + if (wasHidden) { + // TODO: Move re-appear call here for symmetry? + } } - } else { - if (wasHidden) { - // TODO: Move re-appear call here for symmetry? + } + + if (supportsMutation) { + // TODO: This needs to run whenever there's an insertion or update + // inside a hidden Offscreen tree. + hideOrUnhideAllChildren(offscreenBoundary, isHidden); + } + } else { + if (supportsMutation) { + // TODO: This needs to run whenever there's an insertion or update + // inside a hidden Offscreen tree. + hideOrUnhideAllChildren(offscreenBoundary, isHidden); + } + + if (enableSuspenseLayoutEffectSemantics) { + if (isHidden) { + if (!wasHidden) { + if ((offscreenBoundary.mode & ConcurrentMode) !== NoMode) { + nextEffect = offscreenBoundary; + let offscreenChild = offscreenBoundary.child; + while (offscreenChild !== null) { + nextEffect = offscreenChild; + disappearLayoutEffects_begin(offscreenChild); + offscreenChild = offscreenChild.sibling; + } + } + } + } else { + if (wasHidden) { + // TODO: Move re-appear call here for symmetry? + } } } } diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 7b76a1f7524cb..c3c65214e4b52 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -38,6 +38,7 @@ export const skipUnmountedBoundaries = true; // // TODO: Finish rolling out in www export const enableSuspenseLayoutEffectSemantics = true; +export const enableFlipOffscreenUnhideOrder = false; // TODO: Finish rolling out in www export const enableClientRenderFallbackOnTextMismatch = true; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index ea80fba1da246..dcd338c5bc976 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -59,6 +59,7 @@ export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; export const deletedTreeCleanUpLevel = 3; export const enableSuspenseLayoutEffectSemantics = false; +export const enableFlipOffscreenUnhideOrder = false; export const enableGetInspectorDataForInstanceInProduction = true; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 9a5c2bca40a7c..7bd8fd8320808 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -49,6 +49,7 @@ export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; export const deletedTreeCleanUpLevel = 3; export const enableSuspenseLayoutEffectSemantics = false; +export const enableFlipOffscreenUnhideOrder = false; export const enableGetInspectorDataForInstanceInProduction = false; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 157fda232ed38..f24d692b3a16e 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -49,6 +49,7 @@ export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; export const deletedTreeCleanUpLevel = 3; export const enableSuspenseLayoutEffectSemantics = false; +export const enableFlipOffscreenUnhideOrder = false; export const enableGetInspectorDataForInstanceInProduction = false; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js index 0a770e1438a8a..69be474100396 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js @@ -44,6 +44,7 @@ export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; export const deletedTreeCleanUpLevel = 3; export const enableSuspenseLayoutEffectSemantics = false; +export const enableFlipOffscreenUnhideOrder = false; export const enableGetInspectorDataForInstanceInProduction = false; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 157f9d6a41527..6100e7db998da 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -49,6 +49,7 @@ export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; export const deletedTreeCleanUpLevel = 3; export const enableSuspenseLayoutEffectSemantics = false; +export const enableFlipOffscreenUnhideOrder = false; export const enableGetInspectorDataForInstanceInProduction = false; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = false; diff --git a/packages/shared/forks/ReactFeatureFlags.testing.js b/packages/shared/forks/ReactFeatureFlags.testing.js index 072c58b5c8ec6..bce4d6c114b09 100644 --- a/packages/shared/forks/ReactFeatureFlags.testing.js +++ b/packages/shared/forks/ReactFeatureFlags.testing.js @@ -49,6 +49,7 @@ export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; export const deletedTreeCleanUpLevel = 3; export const enableSuspenseLayoutEffectSemantics = false; +export const enableFlipOffscreenUnhideOrder = false; export const enableGetInspectorDataForInstanceInProduction = false; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = false; diff --git a/packages/shared/forks/ReactFeatureFlags.testing.www.js b/packages/shared/forks/ReactFeatureFlags.testing.www.js index a607e3ea7f71c..22b96d4ec7a33 100644 --- a/packages/shared/forks/ReactFeatureFlags.testing.www.js +++ b/packages/shared/forks/ReactFeatureFlags.testing.www.js @@ -49,6 +49,7 @@ export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = true; export const deletedTreeCleanUpLevel = 3; export const enableSuspenseLayoutEffectSemantics = false; +export const enableFlipOffscreenUnhideOrder = false; export const enableGetInspectorDataForInstanceInProduction = false; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = false; diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index 7a89e41ad54f2..ab0a2e1aa41ca 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -29,6 +29,7 @@ export const enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay = __ export const enableClientRenderFallbackOnTextMismatch = __VARIANT__; export const enableTransitionTracing = __VARIANT__; export const enableSymbolFallbackForWWW = __VARIANT__; +export const enableFlipOffscreenUnhideOrder = __VARIANT__; // Enable this flag to help with concurrent mode debugging. // It logs information to the console about React scheduling, rendering, and commit phases. // diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index a1932e21c4e1e..2f222b2e6140f 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -33,6 +33,7 @@ export const { enableSyncDefaultUpdates, enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay, enableClientRenderFallbackOnTextMismatch, + enableFlipOffscreenUnhideOrder, } = dynamicFeatureFlags; // On WWW, __EXPERIMENTAL__ is used for a new modern build.