diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index a68e489dccc98..f9d9ad39999f5 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -2131,8 +2131,7 @@ function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) { } break; } - case OffscreenComponent: - case LegacyHiddenComponent: { + case OffscreenComponent: { const newState: OffscreenState | null = finishedWork.memoizedState; const isHidden = newState !== null; const current = finishedWork.alternate; @@ -2145,27 +2144,26 @@ function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) { hideOrUnhideAllChildren(offscreenBoundary, isHidden); } - if (isHidden) { - if (!wasHidden) { - if ( - enableSuspenseLayoutEffectSemantics && - (offscreenBoundary.mode & ConcurrentMode) !== NoMode - ) { - nextEffect = offscreenBoundary; - let offscreenChild = offscreenBoundary.child; - while (offscreenChild !== null) { - nextEffect = offscreenChild; - disappearLayoutEffects_begin(offscreenChild); - offscreenChild = offscreenChild.sibling; + 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? - } + break; } - break; } } } diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.old.js b/packages/react-reconciler/src/ReactFiberCommitWork.old.js index aea3e36ed09d2..60c230cd251be 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.old.js @@ -2131,8 +2131,7 @@ function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) { } break; } - case OffscreenComponent: - case LegacyHiddenComponent: { + case OffscreenComponent: { const newState: OffscreenState | null = finishedWork.memoizedState; const isHidden = newState !== null; const current = finishedWork.alternate; @@ -2145,27 +2144,26 @@ function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) { hideOrUnhideAllChildren(offscreenBoundary, isHidden); } - if (isHidden) { - if (!wasHidden) { - if ( - enableSuspenseLayoutEffectSemantics && - (offscreenBoundary.mode & ConcurrentMode) !== NoMode - ) { - nextEffect = offscreenBoundary; - let offscreenChild = offscreenBoundary.child; - while (offscreenChild !== null) { - nextEffect = offscreenChild; - disappearLayoutEffects_begin(offscreenChild); - offscreenChild = offscreenChild.sibling; + 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? - } + break; } - break; } } } diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js index 32b9587f26314..b6feee098b4f4 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js @@ -1361,7 +1361,9 @@ function completeWork( const prevIsHidden = prevState !== null; if ( prevIsHidden !== nextIsHidden && - newProps.mode !== 'unstable-defer-without-hiding' + newProps.mode !== 'unstable-defer-without-hiding' && + // LegacyHidden doesn't do any hiding — it only pre-renders. + workInProgress.tag !== LegacyHiddenComponent ) { workInProgress.flags |= Visibility; } diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.old.js b/packages/react-reconciler/src/ReactFiberCompleteWork.old.js index 60359fd42d8de..612ad2db52c9f 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.old.js @@ -1361,7 +1361,9 @@ function completeWork( const prevIsHidden = prevState !== null; if ( prevIsHidden !== nextIsHidden && - newProps.mode !== 'unstable-defer-without-hiding' + newProps.mode !== 'unstable-defer-without-hiding' && + // LegacyHidden doesn't do any hiding — it only pre-renders. + workInProgress.tag !== LegacyHiddenComponent ) { workInProgress.flags |= Visibility; } diff --git a/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js b/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js index 2915b1e769f04..9f9225fea3bad 100644 --- a/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js +++ b/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js @@ -337,4 +337,52 @@ describe('ReactOffscreen', () => { expect(root).toMatchRenderedOutput(); } }); + + // @gate experimental || www + it('does not toggle effects for LegacyHidden component', async () => { + // LegacyHidden is meant to be the same as offscreen except it doesn't + // do anything to effects. Only used by www, as a temporary migration step. + function Child({text}) { + useLayoutEffect(() => { + Scheduler.unstable_yieldValue('Mount layout'); + return () => { + Scheduler.unstable_yieldValue('Unmount layout'); + }; + }, []); + return ; + } + + const root = ReactNoop.createRoot(); + await act(async () => { + root.render( + + + , + ); + }); + expect(Scheduler).toHaveYielded(['Child', 'Mount layout']); + + await act(async () => { + root.render( + + + , + ); + }); + expect(Scheduler).toHaveYielded(['Child']); + + await act(async () => { + root.render( + + + , + ); + }); + expect(Scheduler).toHaveYielded(['Child']); + + await act(async () => { + root.render(null); + }); + expect(Scheduler).toHaveYielded(['Unmount layout']); + }); });