@samitouri / QOS-React-2 / commits / 73962c3664

Revert "Revert "Double-render function components with Hooks in DEV in StrictMode" (#14652)" (#14654)

This reverts commit 3fbebb2a0b3b806f428c4154700af8e75e561895.

Dan Abramov committed Jan 23, 2019 at 19:12 UTC 73962c36645171a7a897bb0fb58e3442d0bb6bc9
2 files changed +273
packages/react-reconciler/src/ReactFiberBeginWork.js
+53
@@ -250,6 +250,23 @@ function updateForwardRef(
250 ref,
251 renderExpirationTime,
252 );
253 + if (
254 + debugRenderPhaseSideEffects ||
255 + (debugRenderPhaseSideEffectsForStrictMode &&
256 + workInProgress.mode & StrictMode)
257 + ) {
258 + // Only double-render components with Hooks
259 + if (workInProgress.memoizedState !== null) {
260 + renderWithHooks(
261 + current,
262 + workInProgress,
263 + render,
264 + nextProps,
265 + ref,
266 + renderExpirationTime,
267 + );
268 + }
269 + }
270 setCurrentPhase(null);
271 } else {
272 nextChildren = renderWithHooks(
@@ -543,6 +560,23 @@ function updateFunctionComponent(
560 context,
561 renderExpirationTime,
562 );
563 + if (
564 + debugRenderPhaseSideEffects ||
565 + (debugRenderPhaseSideEffectsForStrictMode &&
566 + workInProgress.mode & StrictMode)
567 + ) {
568 + // Only double-render components with Hooks
569 + if (workInProgress.memoizedState !== null) {
570 + renderWithHooks(
571 + current,
572 + workInProgress,
573 + Component,
574 + nextProps,
575 + context,
576 + renderExpirationTime,
577 + );
578 + }
579 + }
580 setCurrentPhase(null);
581 } else {
582 nextChildren = renderWithHooks(
@@ -1210,6 +1244,25 @@ function mountIndeterminateComponent(
1244 } else {
1245 // Proceed under the assumption that this is a function component
1246 workInProgress.tag = FunctionComponent;
1247 + if (__DEV__) {
1248 + if (
1249 + debugRenderPhaseSideEffects ||
1250 + (debugRenderPhaseSideEffectsForStrictMode &&
1251 + workInProgress.mode & StrictMode)
1252 + ) {
1253 + // Only double-render components with Hooks
1254 + if (workInProgress.memoizedState !== null) {
1255 + renderWithHooks(
1256 + null,
1257 + workInProgress,
1258 + Component,
1259 + props,
1260 + context,
1261 + renderExpirationTime,
1262 + );
1263 + }
1264 + }
1265 + }
1266 reconcileChildren(null, workInProgress, value, renderExpirationTime);
1267 if (__DEV__) {
1268 validateFunctionComponentInDev(workInProgress, Component);
packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
+220
@@ -841,6 +841,226 @@ describe('ReactHooks', () => {
841 );
842 });
843
844 + it('double-invokes components with Hooks in Strict Mode', () => {
845 + ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = true;
846 +
847 + const {useState, StrictMode} = React;
848 + let renderCount = 0;
849 +
850 + function NoHooks() {
851 + renderCount++;
852 + return <div />;
853 + }
854 +
855 + function HasHooks() {
856 + useState(0);
857 + renderCount++;
858 + return <div />;
859 + }
860 +
861 + const FwdRef = React.forwardRef((props, ref) => {
862 + renderCount++;
863 + return <div />;
864 + });
865 +
866 + const FwdRefHasHooks = React.forwardRef((props, ref) => {
867 + useState(0);
868 + renderCount++;
869 + return <div />;
870 + });
871 +
872 + const Memo = React.memo(props => {
873 + renderCount++;
874 + return <div />;
875 + });
876 +
877 + const MemoHasHooks = React.memo(props => {
878 + useState(0);
879 + renderCount++;
880 + return <div />;
881 + });
882 +
883 + function Factory() {
884 + return {
885 + state: {},
886 + render() {
887 + renderCount++;
888 + return <div />;
889 + },
890 + };
891 + }
892 +
893 + let renderer = ReactTestRenderer.create(null);
894 +
895 + renderCount = 0;
896 + renderer.update(<NoHooks />);
897 + expect(renderCount).toBe(1);
898 + renderCount = 0;
899 + renderer.update(<NoHooks />);
900 + expect(renderCount).toBe(1);
901 + renderCount = 0;
902 + renderer.update(
903 + <StrictMode>
904 + <NoHooks />
905 + </StrictMode>,
906 + );
907 + expect(renderCount).toBe(1);
908 + renderCount = 0;
909 + renderer.update(
910 + <StrictMode>
911 + <NoHooks />
912 + </StrictMode>,
913 + );
914 + expect(renderCount).toBe(1);
915 +
916 + renderCount = 0;
917 + renderer.update(<FwdRef />);
918 + expect(renderCount).toBe(1);
919 + renderCount = 0;
920 + renderer.update(<FwdRef />);
921 + expect(renderCount).toBe(1);
922 + renderCount = 0;
923 + renderer.update(
924 + <StrictMode>
925 + <FwdRef />
926 + </StrictMode>,
927 + );
928 + expect(renderCount).toBe(1);
929 + renderCount = 0;
930 + renderer.update(
931 + <StrictMode>
932 + <FwdRef />
933 + </StrictMode>,
934 + );
935 + expect(renderCount).toBe(1);
936 +
937 + renderCount = 0;
938 + renderer.update(<Memo arg={1} />);
939 + expect(renderCount).toBe(1);
940 + renderCount = 0;
941 + renderer.update(<Memo arg={2} />);
942 + expect(renderCount).toBe(1);
943 + renderCount = 0;
944 + renderer.update(
945 + <StrictMode>
946 + <Memo arg={1} />
947 + </StrictMode>,
948 + );
949 + expect(renderCount).toBe(1);
950 + renderCount = 0;
951 + renderer.update(
952 + <StrictMode>
953 + <Memo arg={2} />
954 + </StrictMode>,
955 + );
956 + expect(renderCount).toBe(1);
957 +
958 + renderCount = 0;
959 + renderer.update(<Factory />);
960 + expect(renderCount).toBe(1);
961 + renderCount = 0;
962 + renderer.update(<Factory />);
963 + expect(renderCount).toBe(1);
964 + renderCount = 0;
965 + renderer.update(
966 + <StrictMode>
967 + <Factory />
968 + </StrictMode>,
969 + );
970 + expect(renderCount).toBe(__DEV__ ? 2 : 1); // Treated like a class
971 + renderCount = 0;
972 + renderer.update(
973 + <StrictMode>
974 + <Factory />
975 + </StrictMode>,
976 + );
977 + expect(renderCount).toBe(__DEV__ ? 2 : 1); // Treated like a class
978 +
979 + renderCount = 0;
980 + renderer.update(<HasHooks />);
981 + expect(renderCount).toBe(1);
982 + renderCount = 0;
983 + renderer.update(<HasHooks />);
984 + expect(renderCount).toBe(1);
985 + renderCount = 0;
986 + renderer.update(
987 + <StrictMode>
988 + <HasHooks />
989 + </StrictMode>,
990 + );
991 + expect(renderCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
992 + renderCount = 0;
993 + renderer.update(
994 + <StrictMode>
995 + <HasHooks />
996 + </StrictMode>,
997 + );
998 + expect(renderCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
999 +
1000 + renderCount = 0;
1001 + renderer.update(<FwdRefHasHooks />);
1002 + expect(renderCount).toBe(1);
1003 + renderCount = 0;
1004 + renderer.update(<FwdRefHasHooks />);
1005 + expect(renderCount).toBe(1);
1006 + renderCount = 0;
1007 + renderer.update(
1008 + <StrictMode>
1009 + <FwdRefHasHooks />
1010 + </StrictMode>,
1011 + );
1012 + expect(renderCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
1013 + renderCount = 0;
1014 + renderer.update(
1015 + <StrictMode>
1016 + <FwdRefHasHooks />
1017 + </StrictMode>,
1018 + );
1019 + expect(renderCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
1020 +
1021 + renderCount = 0;
1022 + renderer.update(<MemoHasHooks arg={1} />);
1023 + expect(renderCount).toBe(1);
1024 + renderCount = 0;
1025 + renderer.update(<MemoHasHooks arg={2} />);
1026 + expect(renderCount).toBe(1);
1027 + renderCount = 0;
1028 + renderer.update(
1029 + <StrictMode>
1030 + <MemoHasHooks arg={1} />
1031 + </StrictMode>,
1032 + );
1033 + expect(renderCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
1034 + renderCount = 0;
1035 + renderer.update(
1036 + <StrictMode>
1037 + <MemoHasHooks arg={2} />
1038 + </StrictMode>,
1039 + );
1040 + expect(renderCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
1041 + });
1042 +
1043 + it('double-invokes useMemo in DEV StrictMode despite []', () => {
1044 + ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = true;
1045 + const {useMemo, StrictMode} = React;
1046 +
1047 + let useMemoCount = 0;
1048 + function BadUseMemo() {
1049 + useMemo(() => {
1050 + useMemoCount++;
1051 + }, []);
1052 + return <div />;
1053 + }
1054 +
1055 + useMemoCount = 0;
1056 + ReactTestRenderer.create(
1057 + <StrictMode>
1058 + <BadUseMemo />
1059 + </StrictMode>,
1060 + );
1061 + expect(useMemoCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
1062 + });
1063 +
1064 it('warns on using differently ordered hooks on subsequent renders', () => {
1065 const {useState, useReducer} = React;
1066 function useCustomHook() {