diff --git a/packages/react-reconciler/src/__tests__/ReactOffscreenSuspense-test.js b/packages/react-reconciler/src/__tests__/ReactOffscreenSuspense-test.js index c73e3caf62..6830bcb426 100644 --- a/packages/react-reconciler/src/__tests__/ReactOffscreenSuspense-test.js +++ b/packages/react-reconciler/src/__tests__/ReactOffscreenSuspense-test.js @@ -7,6 +7,7 @@ let Offscreen; let Suspense; let useState; let useEffect; +let useLayoutEffect; let startTransition; let textCache; let waitFor; @@ -26,6 +27,7 @@ describe('ReactOffscreen', () => { Suspense = React.Suspense; useState = React.useState; useEffect = React.useEffect; + useLayoutEffect = React.useLayoutEffect; startTransition = React.startTransition; const InternalTestUtils = require('internal-test-utils'); @@ -551,4 +553,62 @@ describe('ReactOffscreen', () => { , ); }); + + it('unmounts/mounts layout effects when re-suspending', async () => { + function Child({children}) { + useLayoutEffect(() => { + Scheduler.log('Mount layout'); + return () => { + Scheduler.log('Unmount layout'); + }; + }, []); + return {children}; + } + + const root = ReactNoop.createRoot(); + await act(() => { + root.render( + Loading}> + + + + , + ); + }); + assertLog(['Suspend! [Initial content]']); + expect(root).toMatchRenderedOutput(Loading); + + // Resolve suspense, layout effect is mounted. + await act(() => { + resolveText('Initial content'); + }); + assertLog(['Initial content', 'Mount layout']); + expect(root).toMatchRenderedOutput(Initial content); + + // Re-suspend, the layout effect is unmounted and content is hidden. + await act(() => { + root.render( + Loading}> + + + + , + ); + }); + assertLog(['Suspend! [Re-suspend]', 'Unmount layout']); + expect(root).toMatchRenderedOutput( + <> + + Loading + , + ); + + // Resolve suspense again, layout effect is re-mounted. + await act(() => { + resolveText('Re-suspend'); + }); + + assertLog(['Re-suspend', 'Mount layout']); + expect(root).toMatchRenderedOutput(Re-suspend); + }); });