@@ -772,4 +772,177 @@ describe('StrictEffectsMode', () => {
772
772
'useEffect unmount' ,
773
773
] ) ;
774
774
} ) ;
775
+
776
+ // @gate __DEV__
777
+ it ( 'should double invoke effects after a re-suspend' , async ( ) => {
778
+ // Not using Scheduler.log because it silences double render logs.
779
+ let log = [ ] ;
780
+ let shouldSuspend = true ;
781
+ let resolve ;
782
+ let suspensePromise = new Promise ( _resolve => {
783
+ resolve = _resolve ;
784
+ } ) ;
785
+ function Fallback ( ) {
786
+ log . push ( 'Fallback' ) ;
787
+ return 'Loading' ;
788
+ }
789
+
790
+ function Parent ( { prop} ) {
791
+ log . push ( 'Parent rendered' ) ;
792
+
793
+ React . useEffect ( ( ) => {
794
+ log . push ( 'Parent create' ) ;
795
+ return ( ) => {
796
+ log . push ( 'Parent destroy' ) ;
797
+ } ;
798
+ } , [ ] ) ;
799
+
800
+ React . useEffect ( ( ) => {
801
+ log . push ( 'Parent dep create' ) ;
802
+ return ( ) => {
803
+ log . push ( 'Parent dep destroy' ) ;
804
+ } ;
805
+ } , [ prop ] ) ;
806
+
807
+ return (
808
+ < React . Suspense fallback = { < Fallback /> } >
809
+ < Child prop = { prop } />
810
+ </ React . Suspense >
811
+ ) ;
812
+ }
813
+
814
+ function Child ( { prop} ) {
815
+ const [ count , forceUpdate ] = React . useState ( 0 ) ;
816
+ const ref = React . useRef ( null ) ;
817
+ log . push ( 'Child rendered' ) ;
818
+ React . useEffect ( ( ) => {
819
+ log . push ( 'Child create' ) ;
820
+ return ( ) => {
821
+ log . push ( 'Child destroy' ) ;
822
+ ref . current = true ;
823
+ } ;
824
+ } , [ ] ) ;
825
+ const key = `${ prop } -${ count } ` ;
826
+ React . useEffect ( ( ) => {
827
+ log . push ( 'Child dep create' ) ;
828
+ if ( ref . current === true ) {
829
+ ref . current = false ;
830
+ forceUpdate ( c => c + 1 ) ;
831
+ log . push ( '-----------------------after setState' ) ;
832
+ return ;
833
+ }
834
+
835
+ return ( ) => {
836
+ log . push ( 'Child dep destroy' ) ;
837
+ } ;
838
+ } , [ key ] ) ;
839
+
840
+ if ( shouldSuspend ) {
841
+ log . push ( 'Child suspended' ) ;
842
+ throw suspensePromise ;
843
+ }
844
+ return null ;
845
+ }
846
+
847
+ // Initial mount
848
+ shouldSuspend = false ;
849
+ await act ( ( ) => {
850
+ ReactNoop . render (
851
+ < React . StrictMode >
852
+ < Parent />
853
+ </ React . StrictMode > ,
854
+ ) ;
855
+ } ) ;
856
+
857
+ // Now re-suspend
858
+ shouldSuspend = true ;
859
+ log = [ ] ;
860
+ await act ( ( ) => {
861
+ ReactNoop . render (
862
+ < React . StrictMode >
863
+ < Parent />
864
+ </ React . StrictMode > ,
865
+ ) ;
866
+ } ) ;
867
+
868
+ // while suspended, update
869
+ log . push ( '-----------------------after update' ) ;
870
+ await act ( ( ) => {
871
+ ReactNoop . render (
872
+ < React . StrictMode >
873
+ < Parent prop = { 'bar' } />
874
+ </ React . StrictMode > ,
875
+ ) ;
876
+ } ) ;
877
+
878
+ // Now resolve and commit
879
+ log . push ( '-----------------------after suspense' ) ;
880
+
881
+ await act ( ( ) => {
882
+ resolve ( ) ;
883
+ shouldSuspend = false ;
884
+ } ) ;
885
+
886
+ if ( gate ( flags => flags . useModernStrictMode ) ) {
887
+ expect ( log ) . toEqual ( [
888
+ 'Parent rendered' ,
889
+ 'Parent rendered' ,
890
+ 'Child rendered' ,
891
+ 'Child suspended' ,
892
+ 'Fallback' ,
893
+ 'Fallback' ,
894
+ '-----------------------after update' ,
895
+ 'Parent rendered' ,
896
+ 'Parent rendered' ,
897
+ 'Child rendered' ,
898
+ 'Child suspended' ,
899
+ 'Fallback' ,
900
+ 'Fallback' ,
901
+ 'Parent dep destroy' ,
902
+ 'Parent dep create' ,
903
+ '-----------------------after suspense' ,
904
+ 'Child rendered' ,
905
+ 'Child rendered' ,
906
+ // !!! Committed, destroy and create effect.
907
+ // !!! The other effect is not destroyed and created
908
+ // !!! because the dep didn't change
909
+ 'Child dep destroy' ,
910
+ 'Child dep create' ,
911
+
912
+ // Double invoke both effects
913
+ 'Child destroy' ,
914
+ 'Child dep destroy' ,
915
+ 'Child create' ,
916
+ 'Child dep create' ,
917
+ // Fires setState
918
+ '-----------------------after setState' ,
919
+ 'Child rendered' ,
920
+ 'Child rendered' ,
921
+ 'Child dep create' ,
922
+ ] ) ;
923
+ } else {
924
+ expect ( log ) . toEqual ( [
925
+ 'Parent rendered' ,
926
+ 'Parent rendered' ,
927
+ 'Child rendered' ,
928
+ 'Child suspended' ,
929
+ 'Fallback' ,
930
+ 'Fallback' ,
931
+ '-----------------------after update' ,
932
+ 'Parent rendered' ,
933
+ 'Parent rendered' ,
934
+ 'Child rendered' ,
935
+ 'Child suspended' ,
936
+ 'Fallback' ,
937
+ 'Fallback' ,
938
+ 'Parent dep destroy' ,
939
+ 'Parent dep create' ,
940
+ '-----------------------after suspense' ,
941
+ 'Child rendered' ,
942
+ 'Child rendered' ,
943
+ 'Child dep destroy' ,
944
+ 'Child dep create' ,
945
+ ] ) ;
946
+ }
947
+ } ) ;
775
948
} ) ;
0 commit comments