@@ -699,6 +699,242 @@ describe('ReactFresh', () => {
699699 }
700700 } ) ;
701701
702+ it ( 'can remount when change function to memo' , async ( ) => {
703+ if ( __DEV__ ) {
704+ await act ( async ( ) => {
705+ await render ( ( ) => {
706+ function Test ( ) {
707+ return < p > hi test</ p > ;
708+ }
709+ $RefreshReg$ ( Test , 'Test' ) ;
710+ return Test ;
711+ } ) ;
712+ } ) ;
713+
714+ // Check the initial render
715+ const el = container . firstChild ;
716+ expect ( el . textContent ) . toBe ( 'hi test' ) ;
717+
718+ // Patch to change function to memo
719+ await act ( async ( ) => {
720+ await patch ( ( ) => {
721+ function Test2 ( ) {
722+ return < p > hi memo</ p > ;
723+ }
724+ const Test = React . memo ( Test2 ) ;
725+ $RefreshReg$ ( Test2 , 'Test2' ) ;
726+ $RefreshReg$ ( Test , 'Test' ) ;
727+ return Test ;
728+ } ) ;
729+ } ) ;
730+
731+ // Check remount
732+ expect ( container . firstChild ) . not . toBe ( el ) ;
733+ const nextEl = container . firstChild ;
734+ expect ( nextEl . textContent ) . toBe ( 'hi memo' ) ;
735+
736+ // Patch back to original function
737+ await act ( async ( ) => {
738+ await patch ( ( ) => {
739+ function Test ( ) {
740+ return < p > hi test</ p > ;
741+ }
742+ $RefreshReg$ ( Test , 'Test' ) ;
743+ return Test ;
744+ } ) ;
745+ } ) ;
746+
747+ // Check final remount
748+ expect ( container . firstChild ) . not . toBe ( nextEl ) ;
749+ const newEl = container . firstChild ;
750+ expect ( newEl . textContent ) . toBe ( 'hi test' ) ;
751+ }
752+ } ) ;
753+
754+ it ( 'can remount when change memo to forwardRef' , async ( ) => {
755+ if ( __DEV__ ) {
756+ await act ( async ( ) => {
757+ await render ( ( ) => {
758+ function Test2 ( ) {
759+ return < p > hi memo</ p > ;
760+ }
761+ const Test = React . memo ( Test2 ) ;
762+ $RefreshReg$ ( Test2 , 'Test2' ) ;
763+ $RefreshReg$ ( Test , 'Test' ) ;
764+ return Test ;
765+ } ) ;
766+ } ) ;
767+ // Check the initial render
768+ const el = container . firstChild ;
769+ expect ( el . textContent ) . toBe ( 'hi memo' ) ;
770+
771+ // Patch to change memo to forwardRef
772+ await act ( async ( ) => {
773+ await patch ( ( ) => {
774+ function Test2 ( ) {
775+ return < p > hi forwardRef</ p > ;
776+ }
777+ const Test = React . forwardRef ( Test2 ) ;
778+ $RefreshReg$ ( Test2 , 'Test2' ) ;
779+ $RefreshReg$ ( Test , 'Test' ) ;
780+ return Test ;
781+ } ) ;
782+ } ) ;
783+ // Check remount
784+ expect ( container . firstChild ) . not . toBe ( el ) ;
785+ const nextEl = container . firstChild ;
786+ expect ( nextEl . textContent ) . toBe ( 'hi forwardRef' ) ;
787+
788+ // Patch back to memo
789+ await act ( async ( ) => {
790+ await patch ( ( ) => {
791+ function Test2 ( ) {
792+ return < p > hi memo</ p > ;
793+ }
794+ const Test = React . memo ( Test2 ) ;
795+ $RefreshReg$ ( Test2 , 'Test2' ) ;
796+ $RefreshReg$ ( Test , 'Test' ) ;
797+ return Test ;
798+ } ) ;
799+ } ) ;
800+ // Check final remount
801+ expect ( container . firstChild ) . not . toBe ( nextEl ) ;
802+ const newEl = container . firstChild ;
803+ expect ( newEl . textContent ) . toBe ( 'hi memo' ) ;
804+ }
805+ } ) ;
806+
807+ it ( 'can remount when change function to forwardRef' , async ( ) => {
808+ if ( __DEV__ ) {
809+ await act ( async ( ) => {
810+ await render ( ( ) => {
811+ function Test ( ) {
812+ return < p > hi test</ p > ;
813+ }
814+ $RefreshReg$ ( Test , 'Test' ) ;
815+ return Test ;
816+ } ) ;
817+ } ) ;
818+
819+ // Check the initial render
820+ const el = container . firstChild ;
821+ expect ( el . textContent ) . toBe ( 'hi test' ) ;
822+
823+ // Patch to change function to forwardRef
824+ await act ( async ( ) => {
825+ await patch ( ( ) => {
826+ function Test2 ( ) {
827+ return < p > hi forwardRef</ p > ;
828+ }
829+ const Test = React . forwardRef ( Test2 ) ;
830+ $RefreshReg$ ( Test2 , 'Test2' ) ;
831+ $RefreshReg$ ( Test , 'Test' ) ;
832+ return Test ;
833+ } ) ;
834+ } ) ;
835+
836+ // Check remount
837+ expect ( container . firstChild ) . not . toBe ( el ) ;
838+ const nextEl = container . firstChild ;
839+ expect ( nextEl . textContent ) . toBe ( 'hi forwardRef' ) ;
840+
841+ // Patch back to a new function
842+ await act ( async ( ) => {
843+ await patch ( ( ) => {
844+ function Test ( ) {
845+ return < p > hi test1</ p > ;
846+ }
847+ $RefreshReg$ ( Test , 'Test' ) ;
848+ return Test ;
849+ } ) ;
850+ } ) ;
851+
852+ // Check final remount
853+ expect ( container . firstChild ) . not . toBe ( nextEl ) ;
854+ const newEl = container . firstChild ;
855+ expect ( newEl . textContent ) . toBe ( 'hi test1' ) ;
856+ }
857+ } ) ;
858+
859+ it ( 'resets state when switching between different component types' , async ( ) => {
860+ if ( __DEV__ ) {
861+ await act ( async ( ) => {
862+ await render ( ( ) => {
863+ function Test ( ) {
864+ const [ count , setCount ] = React . useState ( 0 ) ;
865+ return (
866+ < div onClick = { ( ) => setCount ( c => c + 1 ) } > count: { count } </ div >
867+ ) ;
868+ }
869+ $RefreshReg$ ( Test , 'Test' ) ;
870+ return Test ;
871+ } ) ;
872+ } ) ;
873+
874+ expect ( container . firstChild . textContent ) . toBe ( 'count: 0' ) ;
875+ await act ( async ( ) => {
876+ container . firstChild . click ( ) ;
877+ } ) ;
878+ expect ( container . firstChild . textContent ) . toBe ( 'count: 1' ) ;
879+
880+ await act ( async ( ) => {
881+ await patch ( ( ) => {
882+ function Test2 ( ) {
883+ const [ count , setCount ] = React . useState ( 0 ) ;
884+ return (
885+ < div onClick = { ( ) => setCount ( c => c + 1 ) } > count: { count } </ div >
886+ ) ;
887+ }
888+ const Test = React . memo ( Test2 ) ;
889+ $RefreshReg$ ( Test2 , 'Test2' ) ;
890+ $RefreshReg$ ( Test , 'Test' ) ;
891+ return Test ;
892+ } ) ;
893+ } ) ;
894+
895+ expect ( container . firstChild . textContent ) . toBe ( 'count: 0' ) ;
896+ await act ( async ( ) => {
897+ container . firstChild . click ( ) ;
898+ } ) ;
899+ expect ( container . firstChild . textContent ) . toBe ( 'count: 1' ) ;
900+
901+ await act ( async ( ) => {
902+ await patch ( ( ) => {
903+ const Test = React . forwardRef ( ( props , ref ) => {
904+ const [ count , setCount ] = React . useState ( 0 ) ;
905+ const handleClick = ( ) => setCount ( c => c + 1 ) ;
906+
907+ // Ensure ref is extensible
908+ const divRef = React . useRef ( null ) ;
909+ React . useEffect ( ( ) => {
910+ if ( ref ) {
911+ if ( typeof ref === 'function' ) {
912+ ref ( divRef . current ) ;
913+ } else if ( Object . isExtensible ( ref ) ) {
914+ ref . current = divRef . current ;
915+ }
916+ }
917+ } , [ ref ] ) ;
918+
919+ return (
920+ < div ref = { divRef } onClick = { handleClick } >
921+ count: { count }
922+ </ div >
923+ ) ;
924+ } ) ;
925+ $RefreshReg$ ( Test , 'Test' ) ;
926+ return Test ;
927+ } ) ;
928+ } ) ;
929+
930+ expect ( container . firstChild . textContent ) . toBe ( 'count: 0' ) ;
931+ await act ( async ( ) => {
932+ container . firstChild . click ( ) ;
933+ } ) ;
934+ expect ( container . firstChild . textContent ) . toBe ( 'count: 1' ) ;
935+ }
936+ } ) ;
937+
702938 it ( 'can update simple memo function in isolation' , async ( ) => {
703939 if ( __DEV__ ) {
704940 await render ( ( ) => {
0 commit comments