@@ -653,4 +653,68 @@ describe('ReactIncrementalUpdates', () => {
653
653
expect ( Scheduler ) . toFlushAndYield ( [ 'Commit: goodbye' ] ) ;
654
654
} ) ;
655
655
} ) ;
656
+
657
+ it ( 'when rebasing, does not exclude updates that were already committed, regardless of priority' , async ( ) => {
658
+ const { useState, useLayoutEffect} = React ;
659
+
660
+ let pushToLog ;
661
+ function App ( ) {
662
+ const [ log , setLog ] = useState ( '' ) ;
663
+ pushToLog = msg => {
664
+ setLog ( prevLog => prevLog + msg ) ;
665
+ } ;
666
+
667
+ useLayoutEffect (
668
+ ( ) => {
669
+ Scheduler . unstable_yieldValue ( 'Committed: ' + log ) ;
670
+ if ( log === 'B' ) {
671
+ // Right after B commits, schedule additional updates.
672
+ Scheduler . unstable_runWithPriority (
673
+ Scheduler . unstable_UserBlockingPriority ,
674
+ ( ) => {
675
+ pushToLog ( 'C' ) ;
676
+ } ,
677
+ ) ;
678
+ setLog ( prevLog => prevLog + 'D' ) ;
679
+ }
680
+ } ,
681
+ [ log ] ,
682
+ ) ;
683
+
684
+ return log ;
685
+ }
686
+
687
+ const root = ReactNoop . createRoot ( ) ;
688
+ await ReactNoop . act ( async ( ) => {
689
+ root . render ( < App /> ) ;
690
+ } ) ;
691
+ expect ( Scheduler ) . toHaveYielded ( [ 'Committed: ' ] ) ;
692
+ expect ( root ) . toMatchRenderedOutput ( '' ) ;
693
+
694
+ await ReactNoop . act ( async ( ) => {
695
+ pushToLog ( 'A' ) ;
696
+ Scheduler . unstable_runWithPriority (
697
+ Scheduler . unstable_UserBlockingPriority ,
698
+ ( ) => {
699
+ pushToLog ( 'B' ) ;
700
+ } ,
701
+ ) ;
702
+ } ) ;
703
+ expect ( Scheduler ) . toHaveYielded ( [
704
+ // A and B are pending. B is higher priority, so we'll render that first.
705
+ 'Committed: B' ,
706
+ // Because A comes first in the queue, we're now in rebase mode. B must
707
+ // be rebased on top of A. Also, in a layout effect, we received two new
708
+ // updates: C and D. C is user-blocking and D is synchronous.
709
+ //
710
+ // First render the synchronous update. What we're testing here is that
711
+ // B *is not dropped* even though it has lower than sync priority. That's
712
+ // because we already committed it. However, this render should not
713
+ // include C, because that update wasn't already committed.
714
+ 'Committed: BD' ,
715
+ 'Committed: BCD' ,
716
+ 'Committed: ABCD' ,
717
+ ] ) ;
718
+ expect ( root ) . toMatchRenderedOutput ( 'ABCD' ) ;
719
+ } ) ;
656
720
} ) ;
0 commit comments