diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js index b6feee098b4f4..9416ac45dd4c5 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js @@ -63,6 +63,7 @@ import {NoMode, ConcurrentMode, ProfileMode} from './ReactTypeOfMode'; import { Ref, RefStatic, + Placement, Update, Visibility, NoFlags, @@ -1369,13 +1370,26 @@ function completeWork( } } - // Don't bubble properties for hidden children. - if ( - !nextIsHidden || - includesSomeLane(subtreeRenderLanes, (OffscreenLane: Lane)) || - (workInProgress.mode & ConcurrentMode) === NoMode - ) { + if (!nextIsHidden || (workInProgress.mode & ConcurrentMode) === NoMode) { bubbleProperties(workInProgress); + } else { + // Don't bubble properties for hidden children unless we're rendering + // at offscreen priority. + if (includesSomeLane(subtreeRenderLanes, (OffscreenLane: Lane))) { + bubbleProperties(workInProgress); + if (supportsMutation) { + // Check if there was an insertion or update in the hidden subtree. + // If so, we need to hide those nodes in the commit phase, so + // schedule a visibility effect. + if ( + workInProgress.tag !== LegacyHiddenComponent && + workInProgress.subtreeFlags & (Placement | Update) && + newProps.mode !== 'unstable-defer-without-hiding' + ) { + workInProgress.flags |= Visibility; + } + } + } } if (enableCache) { diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.old.js b/packages/react-reconciler/src/ReactFiberCompleteWork.old.js index 612ad2db52c9f..35d17f871ab93 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.old.js @@ -63,6 +63,7 @@ import {NoMode, ConcurrentMode, ProfileMode} from './ReactTypeOfMode'; import { Ref, RefStatic, + Placement, Update, Visibility, NoFlags, @@ -1369,13 +1370,26 @@ function completeWork( } } - // Don't bubble properties for hidden children. - if ( - !nextIsHidden || - includesSomeLane(subtreeRenderLanes, (OffscreenLane: Lane)) || - (workInProgress.mode & ConcurrentMode) === NoMode - ) { + if (!nextIsHidden || (workInProgress.mode & ConcurrentMode) === NoMode) { bubbleProperties(workInProgress); + } else { + // Don't bubble properties for hidden children unless we're rendering + // at offscreen priority. + if (includesSomeLane(subtreeRenderLanes, (OffscreenLane: Lane))) { + bubbleProperties(workInProgress); + if (supportsMutation) { + // Check if there was an insertion or update in the hidden subtree. + // If so, we need to hide those nodes in the commit phase, so + // schedule a visibility effect. + if ( + workInProgress.tag !== LegacyHiddenComponent && + workInProgress.subtreeFlags & (Placement | Update) && + newProps.mode !== 'unstable-defer-without-hiding' + ) { + workInProgress.flags |= Visibility; + } + } + } } if (enableCache) { diff --git a/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js b/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js index 9f9225fea3bad..4dfd6459a33a3 100644 --- a/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js +++ b/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js @@ -201,14 +201,7 @@ describe('ReactOffscreen', () => { }); // No layout effect. expect(Scheduler).toHaveYielded(['Child']); - if (gate(flags => flags.persistent)) { - expect(root).toMatchRenderedOutput(