@@ -1512,6 +1512,165 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1512
1512
) ;
1513
1513
} ) ;
1514
1514
1515
+ it ( 'does not call lifecycles of a suspended component (hooks)' , async ( ) => {
1516
+ function TextWithLifecycle ( props ) {
1517
+ React . useLayoutEffect (
1518
+ ( ) => {
1519
+ Scheduler . unstable_yieldValue ( `Layout Effect [${ props . text } ]` ) ;
1520
+ return ( ) => {
1521
+ Scheduler . unstable_yieldValue (
1522
+ `Destroy Layout Effect [${ props . text } ]` ,
1523
+ ) ;
1524
+ } ;
1525
+ } ,
1526
+ [ props . text ] ,
1527
+ ) ;
1528
+ React . useEffect (
1529
+ ( ) => {
1530
+ Scheduler . unstable_yieldValue ( `Effect [${ props . text } ]` ) ;
1531
+ return ( ) => {
1532
+ Scheduler . unstable_yieldValue ( `Destroy Effect [${ props . text } ]` ) ;
1533
+ } ;
1534
+ } ,
1535
+ [ props . text ] ,
1536
+ ) ;
1537
+ return < Text { ...props } /> ;
1538
+ }
1539
+
1540
+ function AsyncTextWithLifecycle ( props ) {
1541
+ React . useLayoutEffect (
1542
+ ( ) => {
1543
+ Scheduler . unstable_yieldValue ( `Layout Effect [${ props . text } ]` ) ;
1544
+ return ( ) => {
1545
+ Scheduler . unstable_yieldValue (
1546
+ `Destroy Layout Effect [${ props . text } ]` ,
1547
+ ) ;
1548
+ } ;
1549
+ } ,
1550
+ [ props . text ] ,
1551
+ ) ;
1552
+ React . useEffect (
1553
+ ( ) => {
1554
+ Scheduler . unstable_yieldValue ( `Effect [${ props . text } ]` ) ;
1555
+ return ( ) => {
1556
+ Scheduler . unstable_yieldValue ( `Destroy Effect [${ props . text } ]` ) ;
1557
+ } ;
1558
+ } ,
1559
+ [ props . text ] ,
1560
+ ) ;
1561
+ const text = props . text ;
1562
+ const ms = props . ms ;
1563
+ try {
1564
+ TextResource . read ( [ text , ms ] ) ;
1565
+ Scheduler . unstable_yieldValue ( text ) ;
1566
+ return < span prop = { text } /> ;
1567
+ } catch ( promise ) {
1568
+ if ( typeof promise . then === 'function' ) {
1569
+ Scheduler . unstable_yieldValue ( `Suspend! [${ text } ]` ) ;
1570
+ } else {
1571
+ Scheduler . unstable_yieldValue ( `Error! [${ text } ]` ) ;
1572
+ }
1573
+ throw promise ;
1574
+ }
1575
+ }
1576
+
1577
+ function App ( { text} ) {
1578
+ return (
1579
+ < Suspense fallback = { < TextWithLifecycle text = "Loading..." /> } >
1580
+ < TextWithLifecycle text = "A" />
1581
+ < AsyncTextWithLifecycle ms = { 100 } text = { text } />
1582
+ < TextWithLifecycle text = "C" />
1583
+ </ Suspense >
1584
+ ) ;
1585
+ }
1586
+
1587
+ ReactNoop . renderLegacySyncRoot ( < App text = "B" /> , ( ) =>
1588
+ Scheduler . unstable_yieldValue ( 'Commit root' ) ,
1589
+ ) ;
1590
+ expect ( Scheduler ) . toHaveYielded ( [
1591
+ 'A' ,
1592
+ 'Suspend! [B]' ,
1593
+ 'C' ,
1594
+ 'Loading...' ,
1595
+
1596
+ 'Layout Effect [A]' ,
1597
+ // B's effect should not fire because it suspended
1598
+ // 'Layout Effect [B]',
1599
+ 'Layout Effect [C]' ,
1600
+ 'Layout Effect [Loading...]' ,
1601
+ 'Commit root' ,
1602
+ ] ) ;
1603
+
1604
+ // Flush passive effects.
1605
+ expect ( Scheduler ) . toFlushAndYield ( [
1606
+ 'Effect [A]' ,
1607
+ // B's effect should not fire because it suspended
1608
+ // 'Effect [B]',
1609
+ 'Effect [C]' ,
1610
+ 'Effect [Loading...]' ,
1611
+ ] ) ;
1612
+
1613
+ expect ( ReactNoop ) . toMatchRenderedOutput (
1614
+ < >
1615
+ < span hidden = { true } prop = "A" />
1616
+ < span hidden = { true } prop = "C" />
1617
+ < span prop = "Loading..." />
1618
+ </ > ,
1619
+ ) ;
1620
+
1621
+ Scheduler . unstable_advanceTime ( 500 ) ;
1622
+ await advanceTimers ( 500 ) ;
1623
+
1624
+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [B]' ] ) ;
1625
+
1626
+ expect ( Scheduler ) . toFlushAndYield ( [
1627
+ 'B' ,
1628
+ 'Destroy Layout Effect [Loading...]' ,
1629
+ 'Destroy Effect [Loading...]' ,
1630
+ 'Layout Effect [B]' ,
1631
+ 'Effect [B]' ,
1632
+ ] ) ;
1633
+
1634
+ // Update
1635
+ ReactNoop . renderLegacySyncRoot ( < App text = "B2" /> , ( ) =>
1636
+ Scheduler . unstable_yieldValue ( 'Commit root' ) ,
1637
+ ) ;
1638
+
1639
+ expect ( Scheduler ) . toHaveYielded ( [
1640
+ 'A' ,
1641
+ 'Suspend! [B2]' ,
1642
+ 'C' ,
1643
+ 'Loading...' ,
1644
+
1645
+ // B2's effect should not fire because it suspended
1646
+ // 'Layout Effect [B2]',
1647
+ 'Layout Effect [Loading...]' ,
1648
+ 'Commit root' ,
1649
+ ] ) ;
1650
+
1651
+ // Flush passive effects.
1652
+ expect ( Scheduler ) . toFlushAndYield ( [
1653
+ // B2's effect should not fire because it suspended
1654
+ // 'Effect [B2]',
1655
+ 'Effect [Loading...]' ,
1656
+ ] ) ;
1657
+
1658
+ Scheduler . unstable_advanceTime ( 500 ) ;
1659
+ await advanceTimers ( 500 ) ;
1660
+
1661
+ expect ( Scheduler ) . toHaveYielded ( [ 'Promise resolved [B2]' ] ) ;
1662
+
1663
+ expect ( Scheduler ) . toFlushAndYield ( [
1664
+ 'B2' ,
1665
+ 'Destroy Layout Effect [Loading...]' ,
1666
+ 'Destroy Effect [Loading...]' ,
1667
+ 'Destroy Layout Effect [B]' ,
1668
+ 'Layout Effect [B2]' ,
1669
+ 'Destroy Effect [B]' ,
1670
+ 'Effect [B2]' ,
1671
+ ] ) ;
1672
+ } ) ;
1673
+
1515
1674
it ( 'suspends for longer if something took a long (CPU bound) time to render' , async ( ) => {
1516
1675
function Foo ( { renderContent} ) {
1517
1676
Scheduler . unstable_yieldValue ( 'Foo' ) ;
0 commit comments