@@ -699,4 +699,224 @@ describe('ReactHooks', () => {
699699 'Hooks can only be called inside the body of a function component' ,
700700 ) ;
701701 } ) ;
702+
703+ it ( 'double-invokes components with Hooks in Strict Mode' , ( ) => {
704+ ReactFeatureFlags . debugRenderPhaseSideEffectsForStrictMode = true ;
705+
706+ const { useState, StrictMode} = React ;
707+ let renderCount = 0 ;
708+
709+ function NoHooks ( ) {
710+ renderCount ++ ;
711+ return < div /> ;
712+ }
713+
714+ function HasHooks ( ) {
715+ useState ( 0 ) ;
716+ renderCount ++ ;
717+ return < div /> ;
718+ }
719+
720+ const FwdRef = React . forwardRef ( ( props , ref ) => {
721+ renderCount ++ ;
722+ return < div /> ;
723+ } ) ;
724+
725+ const FwdRefHasHooks = React . forwardRef ( ( props , ref ) => {
726+ useState ( 0 ) ;
727+ renderCount ++ ;
728+ return < div /> ;
729+ } ) ;
730+
731+ const Memo = React . memo ( props => {
732+ renderCount ++ ;
733+ return < div /> ;
734+ } ) ;
735+
736+ const MemoHasHooks = React . memo ( props => {
737+ useState ( 0 ) ;
738+ renderCount ++ ;
739+ return < div /> ;
740+ } ) ;
741+
742+ function Factory ( ) {
743+ return {
744+ state : { } ,
745+ render ( ) {
746+ renderCount ++ ;
747+ return < div /> ;
748+ } ,
749+ } ;
750+ }
751+
752+ let renderer = ReactTestRenderer . create ( null ) ;
753+
754+ renderCount = 0 ;
755+ renderer . update ( < NoHooks /> ) ;
756+ expect ( renderCount ) . toBe ( 1 ) ;
757+ renderCount = 0 ;
758+ renderer . update ( < NoHooks /> ) ;
759+ expect ( renderCount ) . toBe ( 1 ) ;
760+ renderCount = 0 ;
761+ renderer . update (
762+ < StrictMode >
763+ < NoHooks />
764+ </ StrictMode > ,
765+ ) ;
766+ expect ( renderCount ) . toBe ( 1 ) ;
767+ renderCount = 0 ;
768+ renderer . update (
769+ < StrictMode >
770+ < NoHooks />
771+ </ StrictMode > ,
772+ ) ;
773+ expect ( renderCount ) . toBe ( 1 ) ;
774+
775+ renderCount = 0 ;
776+ renderer . update ( < FwdRef /> ) ;
777+ expect ( renderCount ) . toBe ( 1 ) ;
778+ renderCount = 0 ;
779+ renderer . update ( < FwdRef /> ) ;
780+ expect ( renderCount ) . toBe ( 1 ) ;
781+ renderCount = 0 ;
782+ renderer . update (
783+ < StrictMode >
784+ < FwdRef />
785+ </ StrictMode > ,
786+ ) ;
787+ expect ( renderCount ) . toBe ( 1 ) ;
788+ renderCount = 0 ;
789+ renderer . update (
790+ < StrictMode >
791+ < FwdRef />
792+ </ StrictMode > ,
793+ ) ;
794+ expect ( renderCount ) . toBe ( 1 ) ;
795+
796+ renderCount = 0 ;
797+ renderer . update ( < Memo arg = { 1 } /> ) ;
798+ expect ( renderCount ) . toBe ( 1 ) ;
799+ renderCount = 0 ;
800+ renderer . update ( < Memo arg = { 2 } /> ) ;
801+ expect ( renderCount ) . toBe ( 1 ) ;
802+ renderCount = 0 ;
803+ renderer . update (
804+ < StrictMode >
805+ < Memo arg = { 1 } />
806+ </ StrictMode > ,
807+ ) ;
808+ expect ( renderCount ) . toBe ( 1 ) ;
809+ renderCount = 0 ;
810+ renderer . update (
811+ < StrictMode >
812+ < Memo arg = { 2 } />
813+ </ StrictMode > ,
814+ ) ;
815+ expect ( renderCount ) . toBe ( 1 ) ;
816+
817+ renderCount = 0 ;
818+ renderer . update ( < Factory /> ) ;
819+ expect ( renderCount ) . toBe ( 1 ) ;
820+ renderCount = 0 ;
821+ renderer . update ( < Factory /> ) ;
822+ expect ( renderCount ) . toBe ( 1 ) ;
823+ renderCount = 0 ;
824+ renderer . update (
825+ < StrictMode >
826+ < Factory />
827+ </ StrictMode > ,
828+ ) ;
829+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Treated like a class
830+ renderCount = 0 ;
831+ renderer . update (
832+ < StrictMode >
833+ < Factory />
834+ </ StrictMode > ,
835+ ) ;
836+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Treated like a class
837+
838+ renderCount = 0 ;
839+ renderer . update ( < HasHooks /> ) ;
840+ expect ( renderCount ) . toBe ( 1 ) ;
841+ renderCount = 0 ;
842+ renderer . update ( < HasHooks /> ) ;
843+ expect ( renderCount ) . toBe ( 1 ) ;
844+ renderCount = 0 ;
845+ renderer . update (
846+ < StrictMode >
847+ < HasHooks />
848+ </ StrictMode > ,
849+ ) ;
850+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
851+ renderCount = 0 ;
852+ renderer . update (
853+ < StrictMode >
854+ < HasHooks />
855+ </ StrictMode > ,
856+ ) ;
857+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
858+
859+ renderCount = 0 ;
860+ renderer . update ( < FwdRefHasHooks /> ) ;
861+ expect ( renderCount ) . toBe ( 1 ) ;
862+ renderCount = 0 ;
863+ renderer . update ( < FwdRefHasHooks /> ) ;
864+ expect ( renderCount ) . toBe ( 1 ) ;
865+ renderCount = 0 ;
866+ renderer . update (
867+ < StrictMode >
868+ < FwdRefHasHooks />
869+ </ StrictMode > ,
870+ ) ;
871+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
872+ renderCount = 0 ;
873+ renderer . update (
874+ < StrictMode >
875+ < FwdRefHasHooks />
876+ </ StrictMode > ,
877+ ) ;
878+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
879+
880+ renderCount = 0 ;
881+ renderer . update ( < MemoHasHooks arg = { 1 } /> ) ;
882+ expect ( renderCount ) . toBe ( 1 ) ;
883+ renderCount = 0 ;
884+ renderer . update ( < MemoHasHooks arg = { 2 } /> ) ;
885+ expect ( renderCount ) . toBe ( 1 ) ;
886+ renderCount = 0 ;
887+ renderer . update (
888+ < StrictMode >
889+ < MemoHasHooks arg = { 1 } />
890+ </ StrictMode > ,
891+ ) ;
892+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
893+ renderCount = 0 ;
894+ renderer . update (
895+ < StrictMode >
896+ < MemoHasHooks arg = { 2 } />
897+ </ StrictMode > ,
898+ ) ;
899+ expect ( renderCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
900+ } ) ;
901+
902+ it ( 'double-invokes useMemo in DEV StrictMode despite []' , ( ) => {
903+ ReactFeatureFlags . debugRenderPhaseSideEffectsForStrictMode = true ;
904+ const { useMemo, StrictMode} = React ;
905+
906+ let useMemoCount = 0 ;
907+ function BadUseMemo ( ) {
908+ useMemo ( ( ) => {
909+ useMemoCount ++ ;
910+ } , [ ] ) ;
911+ return < div /> ;
912+ }
913+
914+ useMemoCount = 0 ;
915+ ReactTestRenderer . create (
916+ < StrictMode >
917+ < BadUseMemo />
918+ </ StrictMode > ,
919+ ) ;
920+ expect ( useMemoCount ) . toBe ( __DEV__ ? 2 : 1 ) ; // Has Hooks
921+ } ) ;
702922} ) ;
0 commit comments