@@ -15,6 +15,7 @@ let ReactNoop;
15
15
let Scheduler ;
16
16
let Suspense ;
17
17
let useState ;
18
+ let useLayoutEffect ;
18
19
let useTransition ;
19
20
let startTransition ;
20
21
let act ;
@@ -30,6 +31,7 @@ describe('ReactTransition', () => {
30
31
ReactNoop = require ( 'react-noop-renderer' ) ;
31
32
Scheduler = require ( 'scheduler' ) ;
32
33
useState = React . useState ;
34
+ useLayoutEffect = React . useLayoutEffect ;
33
35
useTransition = React . unstable_useTransition ;
34
36
Suspense = React . Suspense ;
35
37
startTransition = React . unstable_startTransition ;
@@ -773,4 +775,204 @@ describe('ReactTransition', () => {
773
775
} ) ;
774
776
} ,
775
777
) ;
778
+
779
+ // @gate experimental
780
+ // @gate enableCache
781
+ it ( 'should render normal pri updates scheduled after transitions before transitions' , async ( ) => {
782
+ let updateTransitionPri ;
783
+ let updateNormalPri ;
784
+ function App ( ) {
785
+ const [ normalPri , setNormalPri ] = useState ( 0 ) ;
786
+ const [ transitionPri , setTransitionPri ] = useState ( 0 ) ;
787
+ updateTransitionPri = ( ) =>
788
+ startTransition ( ( ) => setTransitionPri ( n => n + 1 ) ) ;
789
+ updateNormalPri = ( ) => setNormalPri ( n => n + 1 ) ;
790
+
791
+ useLayoutEffect ( ( ) => {
792
+ Scheduler . unstable_yieldValue ( 'Commit' ) ;
793
+ } ) ;
794
+
795
+ return (
796
+ < Suspense fallback = { < Text text = "Loading..." /> } >
797
+ < Text text = { 'Transition pri: ' + transitionPri } />
798
+ { ', ' }
799
+ < Text text = { 'Normal pri: ' + normalPri } />
800
+ </ Suspense >
801
+ ) ;
802
+ }
803
+
804
+ const root = ReactNoop . createRoot ( ) ;
805
+ await act ( async ( ) => {
806
+ root . render ( < App /> ) ;
807
+ } ) ;
808
+
809
+ // Initial render.
810
+ expect ( Scheduler ) . toHaveYielded ( [
811
+ 'Transition pri: 0' ,
812
+ 'Normal pri: 0' ,
813
+ 'Commit' ,
814
+ ] ) ;
815
+ expect ( root ) . toMatchRenderedOutput ( 'Transition pri: 0, Normal pri: 0' ) ;
816
+
817
+ await act ( async ( ) => {
818
+ updateTransitionPri ( ) ;
819
+ updateNormalPri ( ) ;
820
+ } ) ;
821
+
822
+ expect ( Scheduler ) . toHaveYielded ( [
823
+ // Normal update first.
824
+ 'Transition pri: 0' ,
825
+ 'Normal pri: 1' ,
826
+ 'Commit' ,
827
+
828
+ // Then transition update.
829
+ 'Transition pri: 1' ,
830
+ 'Normal pri: 1' ,
831
+ 'Commit' ,
832
+ ] ) ;
833
+ expect ( root ) . toMatchRenderedOutput ( 'Transition pri: 1, Normal pri: 1' ) ;
834
+ } ) ;
835
+
836
+ // @gate experimental
837
+ // @gate enableCache
838
+ it ( 'should render normal pri updates before transition suspense retries' , async ( ) => {
839
+ let updateTransitionPri ;
840
+ let updateNormalPri ;
841
+ function App ( ) {
842
+ const [ transitionPri , setTransitionPri ] = useState ( false ) ;
843
+ const [ normalPri , setNormalPri ] = useState ( 0 ) ;
844
+
845
+ updateTransitionPri = ( ) => startTransition ( ( ) => setTransitionPri ( true ) ) ;
846
+ updateNormalPri = ( ) => setNormalPri ( n => n + 1 ) ;
847
+
848
+ useLayoutEffect ( ( ) => {
849
+ Scheduler . unstable_yieldValue ( 'Commit' ) ;
850
+ } ) ;
851
+
852
+ return (
853
+ < Suspense fallback = { < Text text = "Loading..." /> } >
854
+ { transitionPri ? < AsyncText text = "Async" /> : < Text text = "(empty)" /> }
855
+ { ', ' }
856
+ < Text text = { 'Normal pri: ' + normalPri } />
857
+ </ Suspense >
858
+ ) ;
859
+ }
860
+
861
+ const root = ReactNoop . createRoot ( ) ;
862
+ await act ( async ( ) => {
863
+ root . render ( < App /> ) ;
864
+ } ) ;
865
+
866
+ // Initial render.
867
+ expect ( Scheduler ) . toHaveYielded ( [ '(empty)' , 'Normal pri: 0' , 'Commit' ] ) ;
868
+ expect ( root ) . toMatchRenderedOutput ( '(empty), Normal pri: 0' ) ;
869
+
870
+ await act ( async ( ) => {
871
+ updateTransitionPri ( ) ;
872
+ } ) ;
873
+
874
+ expect ( Scheduler ) . toHaveYielded ( [
875
+ // Suspend.
876
+ 'Suspend! [Async]' ,
877
+ 'Normal pri: 0' ,
878
+ 'Loading...' ,
879
+ ] ) ;
880
+ expect ( root ) . toMatchRenderedOutput ( '(empty), Normal pri: 0' ) ;
881
+
882
+ await act ( async ( ) => {
883
+ await resolveText ( 'Async' ) ;
884
+ updateNormalPri ( ) ;
885
+ } ) ;
886
+
887
+ expect ( Scheduler ) . toHaveYielded ( [
888
+ // Normal pri update.
889
+ '(empty)' ,
890
+ 'Normal pri: 1' ,
891
+ 'Commit' ,
892
+
893
+ // Promise resolved, retry flushed.
894
+ 'Async' ,
895
+ 'Normal pri: 1' ,
896
+ 'Commit' ,
897
+ ] ) ;
898
+ expect ( root ) . toMatchRenderedOutput ( 'Async, Normal pri: 1' ) ;
899
+ } ) ;
900
+
901
+ // @gate experimental
902
+ // @gate enableCache
903
+ it ( 'should not interrupt transitions with normal pri updates' , async ( ) => {
904
+ let updateNormalPri ;
905
+ let updateTransitionPri ;
906
+ function App ( ) {
907
+ const [ transitionPri , setTransitionPri ] = useState ( 0 ) ;
908
+ const [ normalPri , setNormalPri ] = useState ( 0 ) ;
909
+ updateTransitionPri = ( ) =>
910
+ startTransition ( ( ) => setTransitionPri ( n => n + 1 ) ) ;
911
+ updateNormalPri = ( ) => setNormalPri ( n => n + 1 ) ;
912
+
913
+ useLayoutEffect ( ( ) => {
914
+ Scheduler . unstable_yieldValue ( 'Commit' ) ;
915
+ } ) ;
916
+ return (
917
+ < >
918
+ < Text text = { 'Transition pri: ' + transitionPri } />
919
+ { ', ' }
920
+ < Text text = { 'Normal pri: ' + normalPri } />
921
+ </ >
922
+ ) ;
923
+ }
924
+
925
+ const root = ReactNoop . createRoot ( ) ;
926
+ await ReactNoop . act ( async ( ) => {
927
+ root . render ( < App /> ) ;
928
+ } ) ;
929
+ expect ( Scheduler ) . toHaveYielded ( [
930
+ 'Transition pri: 0' ,
931
+ 'Normal pri: 0' ,
932
+ 'Commit' ,
933
+ ] ) ;
934
+ expect ( root ) . toMatchRenderedOutput ( 'Transition pri: 0, Normal pri: 0' ) ;
935
+
936
+ await ReactNoop . act ( async ( ) => {
937
+ updateTransitionPri ( ) ;
938
+
939
+ expect ( Scheduler ) . toFlushAndYieldThrough ( [
940
+ // Start transition update.
941
+ 'Transition pri: 1' ,
942
+ ] ) ;
943
+
944
+ // Schedule normal pri update during transition update.
945
+ // This should not interrupt.
946
+ updateNormalPri ( ) ;
947
+ } ) ;
948
+
949
+ if ( gate ( flags => flags . enableNonInterruptingNormalPri ) ) {
950
+ expect ( Scheduler ) . toHaveYielded ( [
951
+ // Finish transition update.
952
+ 'Normal pri: 0' ,
953
+ 'Commit' ,
954
+
955
+ // Normal pri update.
956
+ 'Transition pri: 1' ,
957
+ 'Normal pri: 1' ,
958
+ 'Commit' ,
959
+ ] ) ;
960
+
961
+ expect ( root ) . toMatchRenderedOutput ( 'Transition pri: 1, Normal pri: 1' ) ;
962
+ } else {
963
+ expect ( Scheduler ) . toHaveYielded ( [
964
+ // Interrupt! Render normal pri update.
965
+ 'Transition pri: 0' ,
966
+ 'Normal pri: 1' ,
967
+ 'Commit' ,
968
+
969
+ // Restart transition update.
970
+ 'Transition pri: 1' ,
971
+ 'Normal pri: 1' ,
972
+ 'Commit' ,
973
+ ] ) ;
974
+
975
+ expect ( root ) . toMatchRenderedOutput ( 'Transition pri: 1, Normal pri: 1' ) ;
976
+ }
977
+ } ) ;
776
978
} ) ;
0 commit comments