@@ -310,6 +310,47 @@ describe('ReactOffscreen', () => {
310
310
expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } prop = "Child" /> ) ;
311
311
} ) ;
312
312
313
+ // @gate experimental || www
314
+ // @gate enableSuspenseLayoutEffectSemantics
315
+ // @gate enableFlipOffscreenUnhideOrder
316
+ it ( 'hides children of offscreen after layout effects are destroyed' , async ( ) => {
317
+ const root = ReactNoop . createRoot ( ) ;
318
+ function Child ( { text} ) {
319
+ useLayoutEffect ( ( ) => {
320
+ Scheduler . unstable_yieldValue ( 'Mount layout' ) ;
321
+ return ( ) => {
322
+ // The child should not be hidden yet.
323
+ expect ( root ) . toMatchRenderedOutput ( < span prop = "Child" /> ) ;
324
+ Scheduler . unstable_yieldValue ( 'Unmount layout' ) ;
325
+ } ;
326
+ } , [ ] ) ;
327
+ return < Text text = "Child" /> ;
328
+ }
329
+
330
+ await act ( async ( ) => {
331
+ root . render (
332
+ < Offscreen mode = "visible" >
333
+ < Child />
334
+ </ Offscreen > ,
335
+ ) ;
336
+ } ) ;
337
+ expect ( Scheduler ) . toHaveYielded ( [ 'Child' , 'Mount layout' ] ) ;
338
+ expect ( root ) . toMatchRenderedOutput ( < span prop = "Child" /> ) ;
339
+
340
+ // Hide the tree. The layout effect is unmounted.
341
+ await act ( async ( ) => {
342
+ root . render (
343
+ < Offscreen mode = "hidden" >
344
+ < Child />
345
+ </ Offscreen > ,
346
+ ) ;
347
+ } ) ;
348
+ expect ( Scheduler ) . toHaveYielded ( [ 'Unmount layout' , 'Child' ] ) ;
349
+
350
+ // After the layout effect is unmounted, the child is hidden.
351
+ expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } prop = "Child" /> ) ;
352
+ } ) ;
353
+
313
354
// @gate www
314
355
it ( 'does not toggle effects for LegacyHidden component' , async ( ) => {
315
356
// LegacyHidden is meant to be the same as offscreen except it doesn't
0 commit comments