699
}
700
});
701
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('can remount when change memo inner type from function to forwardRef', async () => {
860
+ if (__DEV__) {
861
+ await act(async () => {
862
+ await render(() => {
863
+ function Test2() {
864
+ return <p>hi memo</p>;
865
+ }
866
+ const Test = React.memo(Test2);
867
+ $RefreshReg$(Test2, 'Test$React.memo');
868
+ $RefreshReg$(Test, 'Test');
869
+ return Test;
870
+ });
871
+ });
872
+
873
+ // Check the initial render
874
+ const el = container.firstChild;
875
+ expect(el.textContent).toBe('hi memo');
876
+
877
+ // Patch to wrap the inner function in forwardRef.
878
+ // The outer type is still a memo, so only the inner family changes.
879
+ await act(async () => {
880
+ await patch(() => {
881
+ function Test2(props, ref) {
882
+ return <p>hi memo forwardRef</p>;
883
+ }
884
+ const Test2Ref = React.forwardRef(Test2);
885
+ const Test = React.memo(Test2Ref);
886
+ $RefreshReg$(Test2, 'Test$React.memo$React.forwardRef');
887
+ $RefreshReg$(Test2Ref, 'Test$React.memo');
888
+ $RefreshReg$(Test, 'Test');
889
+ return Test;
890
+ });
891
+ });
892
+
893
+ // Check remount
894
+ expect(container.firstChild).not.toBe(el);
895
+ const nextEl = container.firstChild;
896
+ expect(nextEl.textContent).toBe('hi memo forwardRef');
897
+
898
+ // Patch back to a plain function inside memo
899
+ await act(async () => {
900
+ await patch(() => {
901
+ function Test2() {
902
+ return <p>hi memo</p>;
903
+ }
904
+ const Test = React.memo(Test2);
905
+ $RefreshReg$(Test2, 'Test$React.memo');
906
+ $RefreshReg$(Test, 'Test');
907
+ return Test;
908
+ });
909
+ });
910
+
911
+ // Check final remount
912
+ expect(container.firstChild).not.toBe(nextEl);
913
+ const newEl = container.firstChild;
914
+ expect(newEl.textContent).toBe('hi memo');
915
+ }
916
+ });
917
+
918
+ it('resets state when switching between different component types', async () => {
919
+ if (__DEV__) {
920
+ await act(async () => {
921
+ await render(() => {
922
+ function Test() {
923
+ const [count, setCount] = React.useState(0);
924
+ return (
925
+ <div onClick={() => setCount(c => c + 1)}>count: {count}</div>
926
+ );
927
+ }
928
+ $RefreshReg$(Test, 'Test');
929
+ return Test;
930
+ });
931
+ });
932
+
933
+ expect(container.firstChild.textContent).toBe('count: 0');
934
+ await act(async () => {
935
+ container.firstChild.click();
936
+ });
937
+ expect(container.firstChild.textContent).toBe('count: 1');
938
+
939
+ await act(async () => {
940
+ await patch(() => {
941
+ function Test2() {
942
+ const [count, setCount] = React.useState(0);
943
+ return (
944
+ <div onClick={() => setCount(c => c + 1)}>count: {count}</div>
945
+ );
946
+ }
947
+ const Test = React.memo(Test2);
948
+ $RefreshReg$(Test2, 'Test2');
949
+ $RefreshReg$(Test, 'Test');
950
+ return Test;
951
+ });
952
+ });
953
+
954
+ expect(container.firstChild.textContent).toBe('count: 0');
955
+ await act(async () => {
956
+ container.firstChild.click();
957
+ });
958
+ expect(container.firstChild.textContent).toBe('count: 1');
959
+
960
+ await act(async () => {
961
+ await patch(() => {
962
+ const Test = React.forwardRef((props, ref) => {
963
+ const [count, setCount] = React.useState(0);
964
+ const handleClick = () => setCount(c => c + 1);
965
+
966
+ // Ensure ref is extensible
967
+ const divRef = React.useRef(null);
968
+ React.useEffect(() => {
969
+ if (ref) {
970
+ if (typeof ref === 'function') {
971
+ ref(divRef.current);
972
+ } else if (Object.isExtensible(ref)) {
973
+ ref.current = divRef.current;
974
+ }
975
+ }
976
+ }, [ref]);
977
+
978
+ return (
979
+ <div ref={divRef} onClick={handleClick}>
980
+ count: {count}
981
+ </div>
982
+ );
983
+ });
984
+ $RefreshReg$(Test, 'Test');
985
+ return Test;
986
+ });
987
+ });
988
+
989
+ expect(container.firstChild.textContent).toBe('count: 0');
990
+ await act(async () => {
991
+ container.firstChild.click();
992
+ });
993
+ expect(container.firstChild.textContent).toBe('count: 1');
994
+ }
995
+ });
996
+
997
it('can update simple memo function in isolation', async () => {
998
if (__DEV__) {
999
await render(() => {