@@ -660,4 +660,224 @@ describe('ReactHooks', () => {
660
660
'Hooks can only be called inside the body of a function component' ,
661
661
) ;
662
662
} ) ;
663
+
664
+ it ( 'double-invokes components with Hooks in Strict Mode' , ( ) => {
665
+ ReactFeatureFlags . debugRenderPhaseSideEffectsForStrictMode = true ;
666
+
667
+ const { useState, StrictMode} = React ;
668
+ let renderCount = 0 ;
669
+
670
+ function NoHooks ( ) {
671
+ renderCount ++ ;
672
+ return < div /> ;
673
+ }
674
+
675
+ function HasHooks ( ) {
676
+ useState ( 0 ) ;
677
+ renderCount ++ ;
678
+ return < div /> ;
679
+ }
680
+
681
+ const FwdRef = React . forwardRef ( ( props , ref ) => {
682
+ renderCount ++ ;
683
+ return < div /> ;
684
+ } ) ;
685
+
686
+ const FwdRefHasHooks = React . forwardRef ( ( props , ref ) => {
687
+ useState ( 0 ) ;
688
+ renderCount ++ ;
689
+ return < div /> ;
690
+ } ) ;
691
+
692
+ const Memo = React . memo ( props => {
693
+ renderCount ++ ;
694
+ return < div /> ;
695
+ } ) ;
696
+
697
+ const MemoHasHooks = React . memo ( props => {
698
+ useState ( 0 ) ;
699
+ renderCount ++ ;
700
+ return < div /> ;
701
+ } ) ;
702
+
703
+ function Factory ( ) {
704
+ return {
705
+ state : { } ,
706
+ render ( ) {
707
+ renderCount ++ ;
708
+ return < div /> ;
709
+ } ,
710
+ } ;
711
+ }
712
+
713
+ let renderer = ReactTestRenderer . create ( null ) ;
714
+
715
+ renderCount = 0 ;
716
+ renderer . update ( < NoHooks /> ) ;
717
+ expect ( renderCount ) . toBe ( 1 ) ;
718
+ renderCount = 0 ;
719
+ renderer . update ( < NoHooks /> ) ;
720
+ expect ( renderCount ) . toBe ( 1 ) ;
721
+ renderCount = 0 ;
722
+ renderer . update (
723
+ < StrictMode >
724
+ < NoHooks />
725
+ </ StrictMode > ,
726
+ ) ;
727
+ expect ( renderCount ) . toBe ( 1 ) ;
728
+ renderCount = 0 ;
729
+ renderer . update (
730
+ < StrictMode >
731
+ < NoHooks />
732
+ </ StrictMode > ,
733
+ ) ;
734
+ expect ( renderCount ) . toBe ( 1 ) ;
735
+
736
+ renderCount = 0 ;
737
+ renderer . update ( < FwdRef /> ) ;
738
+ expect ( renderCount ) . toBe ( 1 ) ;
739
+ renderCount = 0 ;
740
+ renderer . update ( < FwdRef /> ) ;
741
+ expect ( renderCount ) . toBe ( 1 ) ;
742
+ renderCount = 0 ;
743
+ renderer . update (
744
+ < StrictMode >
745
+ < FwdRef />
746
+ </ StrictMode > ,
747
+ ) ;
748
+ expect ( renderCount ) . toBe ( 1 ) ;
749
+ renderCount = 0 ;
750
+ renderer . update (
751
+ < StrictMode >
752
+ < FwdRef />
753
+ </ StrictMode > ,
754
+ ) ;
755
+ expect ( renderCount ) . toBe ( 1 ) ;
756
+
757
+ renderCount = 0 ;
758
+ renderer . update ( < Memo arg = { 1 } /> ) ;
759
+ expect ( renderCount ) . toBe ( 1 ) ;
760
+ renderCount = 0 ;
761
+ renderer . update ( < Memo arg = { 2 } /> ) ;
762
+ expect ( renderCount ) . toBe ( 1 ) ;
763
+ renderCount = 0 ;
764
+ renderer . update (
765
+ < StrictMode >
766
+ < Memo arg = { 1 } />
767
+ </ StrictMode > ,
768
+ ) ;
769
+ expect ( renderCount ) . toBe ( 1 ) ;
770
+ renderCount = 0 ;
771
+ renderer . update (
772
+ < StrictMode >
773
+ < Memo arg = { 2 } />
774
+ </ StrictMode > ,
775
+ ) ;
776
+ expect ( renderCount ) . toBe ( 1 ) ;
777
+
778
+ renderCount = 0 ;
779
+ renderer . update ( < Factory /> ) ;
780
+ expect ( renderCount ) . toBe ( 1 ) ;
781
+ renderCount = 0 ;
782
+ renderer . update ( < Factory /> ) ;
783
+ expect ( renderCount ) . toBe ( 1 ) ;
784
+ renderCount = 0 ;
785
+ renderer . update (
786
+ < StrictMode >
787
+ < Factory />
788
+ </ StrictMode > ,
789
+ ) ;
790
+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Treated like a class
791
+ renderCount = 0 ;
792
+ renderer . update (
793
+ < StrictMode >
794
+ < Factory />
795
+ </ StrictMode > ,
796
+ ) ;
797
+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Treated like a class
798
+
799
+ renderCount = 0 ;
800
+ renderer . update ( < HasHooks /> ) ;
801
+ expect ( renderCount ) . toBe ( 1 ) ;
802
+ renderCount = 0 ;
803
+ renderer . update ( < HasHooks /> ) ;
804
+ expect ( renderCount ) . toBe ( 1 ) ;
805
+ renderCount = 0 ;
806
+ renderer . update (
807
+ < StrictMode >
808
+ < HasHooks />
809
+ </ StrictMode > ,
810
+ ) ;
811
+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
812
+ renderCount = 0 ;
813
+ renderer . update (
814
+ < StrictMode >
815
+ < HasHooks />
816
+ </ StrictMode > ,
817
+ ) ;
818
+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
819
+
820
+ renderCount = 0 ;
821
+ renderer . update ( < FwdRefHasHooks /> ) ;
822
+ expect ( renderCount ) . toBe ( 1 ) ;
823
+ renderCount = 0 ;
824
+ renderer . update ( < FwdRefHasHooks /> ) ;
825
+ expect ( renderCount ) . toBe ( 1 ) ;
826
+ renderCount = 0 ;
827
+ renderer . update (
828
+ < StrictMode >
829
+ < FwdRefHasHooks />
830
+ </ StrictMode > ,
831
+ ) ;
832
+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
833
+ renderCount = 0 ;
834
+ renderer . update (
835
+ < StrictMode >
836
+ < FwdRefHasHooks />
837
+ </ StrictMode > ,
838
+ ) ;
839
+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
840
+
841
+ renderCount = 0 ;
842
+ renderer . update ( < MemoHasHooks arg = { 1 } /> ) ;
843
+ expect ( renderCount ) . toBe ( 1 ) ;
844
+ renderCount = 0 ;
845
+ renderer . update ( < MemoHasHooks arg = { 2 } /> ) ;
846
+ expect ( renderCount ) . toBe ( 1 ) ;
847
+ renderCount = 0 ;
848
+ renderer . update (
849
+ < StrictMode >
850
+ < MemoHasHooks arg = { 1 } />
851
+ </ StrictMode > ,
852
+ ) ;
853
+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
854
+ renderCount = 0 ;
855
+ renderer . update (
856
+ < StrictMode >
857
+ < MemoHasHooks arg = { 2 } />
858
+ </ StrictMode > ,
859
+ ) ;
860
+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
861
+ } ) ;
862
+
863
+ it ( 'double-invokes useMemo in DEV StrictMode despite []' , ( ) => {
864
+ ReactFeatureFlags . debugRenderPhaseSideEffectsForStrictMode = true ;
865
+ const { useMemo, StrictMode} = React ;
866
+
867
+ let useMemoCount = 0 ;
868
+ function BadUseMemo ( ) {
869
+ useMemo ( ( ) => {
870
+ useMemoCount ++ ;
871
+ } , [ ] ) ;
872
+ return < div /> ;
873
+ }
874
+
875
+ useMemoCount = 0 ;
876
+ ReactTestRenderer . create (
877
+ < StrictMode >
878
+ < BadUseMemo />
879
+ </ StrictMode > ,
880
+ ) ;
881
+ expect ( useMemoCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
882
+ } ) ;
663
883
} ) ;
0 commit comments