@samitouri / QOS-React-2 / commits / 5731e522d4

[Fresh] Support lazy() and add Suspense tests (#15681)

* Test that state is not leaked between components * Support lazy and add Suspense tests * Nits

Dan Abramov committed May 20, 2019 at 14:11 UTC 5731e522d4a14e53bd37bb304f831f1f5e9f9f36
2 files changed +684 -3
packages/react-dom/src/__tests__/ReactFresh-test.internal.js
+676
@@ -895,6 +895,592 @@ describe('ReactFresh', () => {
895 }
896 });
897
898 + it('can preserve state for lazy after resolution', async () => {
899 + if (__DEV__) {
900 + let OuterV1 = render(() => {
901 + function Hello() {
902 + const [val, setVal] = React.useState(0);
903 + return (
904 + <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
905 + {val}
906 + </p>
907 + );
908 + }
909 + __register__(Hello, 'Hello');
910 +
911 + const Outer = React.lazy(
912 + () =>
913 + new Promise(resolve => {
914 + setTimeout(() => resolve({default: Hello}), 100);
915 + }),
916 + );
917 + __register__(Outer, 'Outer');
918 +
919 + function App() {
920 + return (
921 + <React.Suspense fallback={<p>Loading</p>}>
922 + <Outer />
923 + </React.Suspense>
924 + );
925 + }
926 +
927 + return App;
928 + });
929 +
930 + expect(container.textContent).toBe('Loading');
931 + await act(async () => {
932 + jest.runAllTimers();
933 + });
934 + expect(container.textContent).toBe('0');
935 +
936 + // Bump the state before patching.
937 + const el = container.firstChild;
938 + expect(el.textContent).toBe('0');
939 + expect(el.style.color).toBe('blue');
940 + act(() => {
941 + el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
942 + });
943 + expect(el.textContent).toBe('1');
944 +
945 + // Perform a hot update.
946 + patch(() => {
947 + function Hello() {
948 + const [val, setVal] = React.useState(0);
949 + return (
950 + <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
951 + {val}
952 + </p>
953 + );
954 + }
955 + __register__(Hello, 'Hello');
956 + });
957 +
958 + // Assert the state was preserved but color changed.
959 + expect(container.firstChild).toBe(el);
960 + expect(el.textContent).toBe('1');
961 + expect(el.style.color).toBe('red');
962 +
963 + // Bump the state again.
964 + act(() => {
965 + el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
966 + });
967 + expect(container.firstChild).toBe(el);
968 + expect(el.textContent).toBe('2');
969 + expect(el.style.color).toBe('red');
970 +
971 + // Perform a top-down render with a stale type.
972 + render(() => OuterV1);
973 + expect(container.firstChild).toBe(el);
974 + expect(el.textContent).toBe('2');
975 + expect(el.style.color).toBe('red');
976 +
977 + // Finally, a render with incompatible type should reset it.
978 + render(() => {
979 + function Hello() {
980 + const [val, setVal] = React.useState(0);
981 + return (
982 + <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
983 + {val}
984 + </p>
985 + );
986 + }
987 + __register__(Hello, 'Hello');
988 +
989 + // Note: no lazy wrapper this time.
990 + return Hello;
991 + });
992 +
993 + expect(container.firstChild).not.toBe(el);
994 + const newEl = container.firstChild;
995 + expect(newEl.textContent).toBe('0');
996 + expect(newEl.style.color).toBe('blue');
997 + }
998 + });
999 +
1000 + it('can patch lazy before resolution', async () => {
1001 + if (__DEV__) {
1002 + render(() => {
1003 + function Hello() {
1004 + const [val, setVal] = React.useState(0);
1005 + return (
1006 + <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
1007 + {val}
1008 + </p>
1009 + );
1010 + }
1011 + __register__(Hello, 'Hello');
1012 +
1013 + const Outer = React.lazy(
1014 + () =>
1015 + new Promise(resolve => {
1016 + setTimeout(() => resolve({default: Hello}), 100);
1017 + }),
1018 + );
1019 + __register__(Outer, 'Outer');
1020 +
1021 + function App() {
1022 + return (
1023 + <React.Suspense fallback={<p>Loading</p>}>
1024 + <Outer />
1025 + </React.Suspense>
1026 + );
1027 + }
1028 +
1029 + return App;
1030 + });
1031 +
1032 + expect(container.textContent).toBe('Loading');
1033 +
1034 + // Perform a hot update.
1035 + patch(() => {
1036 + function Hello() {
1037 + const [val, setVal] = React.useState(0);
1038 + return (
1039 + <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
1040 + {val}
1041 + </p>
1042 + );
1043 + }
1044 + __register__(Hello, 'Hello');
1045 + });
1046 +
1047 + await act(async () => {
1048 + jest.runAllTimers();
1049 + });
1050 +
1051 + // Expect different color on initial mount.
1052 + const el = container.firstChild;
1053 + expect(el.textContent).toBe('0');
1054 + expect(el.style.color).toBe('red');
1055 +
1056 + // Bump state.
1057 + act(() => {
1058 + el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
1059 + });
1060 + expect(container.firstChild).toBe(el);
1061 + expect(el.textContent).toBe('1');
1062 + expect(el.style.color).toBe('red');
1063 +
1064 + // Test another reload.
1065 + patch(() => {
1066 + function Hello() {
1067 + const [val, setVal] = React.useState(0);
1068 + return (
1069 + <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
1070 + {val}
1071 + </p>
1072 + );
1073 + }
1074 + __register__(Hello, 'Hello');
1075 + });
1076 + expect(container.firstChild).toBe(el);
1077 + expect(el.textContent).toBe('1');
1078 + expect(el.style.color).toBe('orange');
1079 + }
1080 + });
1081 +
1082 + it('can patch lazy(forwardRef) before resolution', async () => {
1083 + if (__DEV__) {
1084 + render(() => {
1085 + function renderHello() {
1086 + const [val, setVal] = React.useState(0);
1087 + return (
1088 + <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
1089 + {val}
1090 + </p>
1091 + );
1092 + }
1093 + const Hello = React.forwardRef(renderHello);
1094 + __register__(Hello, 'Hello');
1095 +
1096 + const Outer = React.lazy(
1097 + () =>
1098 + new Promise(resolve => {
1099 + setTimeout(() => resolve({default: Hello}), 100);
1100 + }),
1101 + );
1102 + __register__(Outer, 'Outer');
1103 +
1104 + function App() {
1105 + return (
1106 + <React.Suspense fallback={<p>Loading</p>}>
1107 + <Outer />
1108 + </React.Suspense>
1109 + );
1110 + }
1111 +
1112 + return App;
1113 + });
1114 +
1115 + expect(container.textContent).toBe('Loading');
1116 +
1117 + // Perform a hot update.
1118 + patch(() => {
1119 + function renderHello() {
1120 + const [val, setVal] = React.useState(0);
1121 + return (
1122 + <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
1123 + {val}
1124 + </p>
1125 + );
1126 + }
1127 + const Hello = React.forwardRef(renderHello);
1128 + __register__(Hello, 'Hello');
1129 + });
1130 +
1131 + await act(async () => {
1132 + jest.runAllTimers();
1133 + });
1134 +
1135 + // Expect different color on initial mount.
1136 + const el = container.firstChild;
1137 + expect(el.textContent).toBe('0');
1138 + expect(el.style.color).toBe('red');
1139 +
1140 + // Bump state.
1141 + act(() => {
1142 + el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
1143 + });
1144 + expect(container.firstChild).toBe(el);
1145 + expect(el.textContent).toBe('1');
1146 + expect(el.style.color).toBe('red');
1147 +
1148 + // Test another reload.
1149 + patch(() => {
1150 + function renderHello() {
1151 + const [val, setVal] = React.useState(0);
1152 + return (
1153 + <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
1154 + {val}
1155 + </p>
1156 + );
1157 + }
1158 + const Hello = React.forwardRef(renderHello);
1159 + __register__(Hello, 'Hello');
1160 + });
1161 + expect(container.firstChild).toBe(el);
1162 + expect(el.textContent).toBe('1');
1163 + expect(el.style.color).toBe('orange');
1164 + }
1165 + });
1166 +
1167 + it('can patch lazy(memo) before resolution', async () => {
1168 + if (__DEV__) {
1169 + render(() => {
1170 + function renderHello() {
1171 + const [val, setVal] = React.useState(0);
1172 + return (
1173 + <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
1174 + {val}
1175 + </p>
1176 + );
1177 + }
1178 + const Hello = React.memo(renderHello);
1179 + __register__(Hello, 'Hello');
1180 +
1181 + const Outer = React.lazy(
1182 + () =>
1183 + new Promise(resolve => {
1184 + setTimeout(() => resolve({default: Hello}), 100);
1185 + }),
1186 + );
1187 + __register__(Outer, 'Outer');
1188 +
1189 + function App() {
1190 + return (
1191 + <React.Suspense fallback={<p>Loading</p>}>
1192 + <Outer />
1193 + </React.Suspense>
1194 + );
1195 + }
1196 +
1197 + return App;
1198 + });
1199 +
1200 + expect(container.textContent).toBe('Loading');
1201 +
1202 + // Perform a hot update.
1203 + patch(() => {
1204 + function renderHello() {
1205 + const [val, setVal] = React.useState(0);
1206 + return (
1207 + <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
1208 + {val}
1209 + </p>
1210 + );
1211 + }
1212 + const Hello = React.memo(renderHello);
1213 + __register__(Hello, 'Hello');
1214 + });
1215 +
1216 + await act(async () => {
1217 + jest.runAllTimers();
1218 + });
1219 +
1220 + // Expect different color on initial mount.
1221 + const el = container.firstChild;
1222 + expect(el.textContent).toBe('0');
1223 + expect(el.style.color).toBe('red');
1224 +
1225 + // Bump state.
1226 + act(() => {
1227 + el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
1228 + });
1229 + expect(container.firstChild).toBe(el);
1230 + expect(el.textContent).toBe('1');
1231 + expect(el.style.color).toBe('red');
1232 +
1233 + // Test another reload.
1234 + patch(() => {
1235 + function renderHello() {
1236 + const [val, setVal] = React.useState(0);
1237 + return (
1238 + <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
1239 + {val}
1240 + </p>
1241 + );
1242 + }
1243 + const Hello = React.memo(renderHello);
1244 + __register__(Hello, 'Hello');
1245 + });
1246 + expect(container.firstChild).toBe(el);
1247 + expect(el.textContent).toBe('1');
1248 + expect(el.style.color).toBe('orange');
1249 + }
1250 + });
1251 +
1252 + it('can patch lazy(memo(forwardRef)) before resolution', async () => {
1253 + if (__DEV__) {
1254 + render(() => {
1255 + function renderHello() {
1256 + const [val, setVal] = React.useState(0);
1257 + return (
1258 + <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
1259 + {val}
1260 + </p>
1261 + );
1262 + }
1263 + const Hello = React.memo(React.forwardRef(renderHello));
1264 + __register__(Hello, 'Hello');
1265 +
1266 + const Outer = React.lazy(
1267 + () =>
1268 + new Promise(resolve => {
1269 + setTimeout(() => resolve({default: Hello}), 100);
1270 + }),
1271 + );
1272 + __register__(Outer, 'Outer');
1273 +
1274 + function App() {
1275 + return (
1276 + <React.Suspense fallback={<p>Loading</p>}>
1277 + <Outer />
1278 + </React.Suspense>
1279 + );
1280 + }
1281 +
1282 + return App;
1283 + });
1284 +
1285 + expect(container.textContent).toBe('Loading');
1286 +
1287 + // Perform a hot update.
1288 + patch(() => {
1289 + function renderHello() {
1290 + const [val, setVal] = React.useState(0);
1291 + return (
1292 + <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
1293 + {val}
1294 + </p>
1295 + );
1296 + }
1297 + const Hello = React.memo(React.forwardRef(renderHello));
1298 + __register__(Hello, 'Hello');
1299 + });
1300 +
1301 + await act(async () => {
1302 + jest.runAllTimers();
1303 + });
1304 +
1305 + // Expect different color on initial mount.
1306 + const el = container.firstChild;
1307 + expect(el.textContent).toBe('0');
1308 + expect(el.style.color).toBe('red');
1309 +
1310 + // Bump state.
1311 + act(() => {
1312 + el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
1313 + });
1314 + expect(container.firstChild).toBe(el);
1315 + expect(el.textContent).toBe('1');
1316 + expect(el.style.color).toBe('red');
1317 +
1318 + // Test another reload.
1319 + patch(() => {
1320 + function renderHello() {
1321 + const [val, setVal] = React.useState(0);
1322 + return (
1323 + <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
1324 + {val}
1325 + </p>
1326 + );
1327 + }
1328 + const Hello = React.memo(React.forwardRef(renderHello));
1329 + __register__(Hello, 'Hello');
1330 + });
1331 + expect(container.firstChild).toBe(el);
1332 + expect(el.textContent).toBe('1');
1333 + expect(el.style.color).toBe('orange');
1334 + }
1335 + });
1336 +
1337 + it('can patch both trees while suspense is displaying the fallback', async () => {
1338 + if (__DEV__) {
1339 + const AppV1 = render(
1340 + () => {
1341 + function Hello({children}) {
1342 + const [val, setVal] = React.useState(0);
1343 + return (
1344 + <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
1345 + {children} {val}
1346 + </p>
1347 + );
1348 + }
1349 + __register__(Hello, 'Hello');
1350 +
1351 + function Never() {
1352 + throw new Promise(resolve => {});
1353 + }
1354 +
1355 + function App({shouldSuspend}) {
1356 + return (
1357 + <React.Suspense fallback={<Hello>Fallback</Hello>}>
1358 + <Hello>Content</Hello>
1359 + {shouldSuspend && <Never />}
1360 + </React.Suspense>
1361 + );
1362 + }
1363 +
1364 + return App;
1365 + },
1366 + {shouldSuspend: false},
1367 + );
1368 +
1369 + // We start with just the primary tree.
1370 + expect(container.childNodes.length).toBe(1);
1371 + const primaryChild = container.firstChild;
1372 + expect(primaryChild.textContent).toBe('Content 0');
1373 + expect(primaryChild.style.color).toBe('blue');
1374 + expect(primaryChild.style.display).toBe('');
1375 +
1376 + // Bump primary content state.
1377 + act(() => {
1378 + primaryChild.dispatchEvent(new MouseEvent('click', {bubbles: true}));
1379 + });
1380 + expect(container.childNodes.length).toBe(1);
1381 + expect(container.childNodes[0]).toBe(primaryChild);
1382 + expect(primaryChild.textContent).toBe('Content 1');
1383 + expect(primaryChild.style.color).toBe('blue');
1384 + expect(primaryChild.style.display).toBe('');
1385 +
1386 + // Perform a hot update.
1387 + patch(() => {
1388 + function Hello({children}) {
1389 + const [val, setVal] = React.useState(0);
1390 + return (
1391 + <p style={{color: 'green'}} onClick={() => setVal(val + 1)}>
1392 + {children} {val}
1393 + </p>
1394 + );
1395 + }
1396 + __register__(Hello, 'Hello');
1397 + });
1398 + expect(container.childNodes.length).toBe(1);
1399 + expect(container.childNodes[0]).toBe(primaryChild);
1400 + expect(primaryChild.textContent).toBe('Content 1');
1401 + expect(primaryChild.style.color).toBe('green');
1402 + expect(primaryChild.style.display).toBe('');
1403 +
1404 + // Now force the tree to suspend.
1405 + render(() => AppV1, {shouldSuspend: true});
1406 +
1407 + // Expect to see two trees, one of them is hidden.
1408 + expect(container.childNodes.length).toBe(2);
1409 + expect(container.childNodes[0]).toBe(primaryChild);
1410 + const fallbackChild = container.childNodes[1];
1411 + expect(primaryChild.textContent).toBe('Content 1');
1412 + expect(primaryChild.style.color).toBe('green');
1413 + expect(primaryChild.style.display).toBe('none');
1414 + expect(fallbackChild.textContent).toBe('Fallback 0');
1415 + expect(fallbackChild.style.color).toBe('green');
1416 + expect(fallbackChild.style.display).toBe('');
1417 +
1418 + // Bump fallback state.
1419 + act(() => {
1420 + fallbackChild.dispatchEvent(new MouseEvent('click', {bubbles: true}));
1421 + });
1422 + expect(container.childNodes.length).toBe(2);
1423 + expect(container.childNodes[0]).toBe(primaryChild);
1424 + expect(container.childNodes[1]).toBe(fallbackChild);
1425 + expect(primaryChild.textContent).toBe('Content 1');
1426 + expect(primaryChild.style.color).toBe('green');
1427 + expect(primaryChild.style.display).toBe('none');
1428 + expect(fallbackChild.textContent).toBe('Fallback 1');
1429 + expect(fallbackChild.style.color).toBe('green');
1430 + expect(fallbackChild.style.display).toBe('');
1431 +
1432 + // Perform a hot update.
1433 + patch(() => {
1434 + function Hello({children}) {
1435 + const [val, setVal] = React.useState(0);
1436 + return (
1437 + <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
1438 + {children} {val}
1439 + </p>
1440 + );
1441 + }
1442 + __register__(Hello, 'Hello');
1443 + });
1444 +
1445 + // Colors inside both trees should change:
1446 + expect(container.childNodes.length).toBe(2);
1447 + expect(container.childNodes[0]).toBe(primaryChild);
1448 + expect(container.childNodes[1]).toBe(fallbackChild);
1449 + expect(primaryChild.textContent).toBe('Content 1');
1450 + expect(primaryChild.style.color).toBe('red');
1451 + expect(primaryChild.style.display).toBe('none');
1452 + expect(fallbackChild.textContent).toBe('Fallback 1');
1453 + expect(fallbackChild.style.color).toBe('red');
1454 + expect(fallbackChild.style.display).toBe('');
1455 +
1456 + // Only primary tree should exist now:
1457 + render(() => AppV1, {shouldSuspend: false});
1458 + expect(container.childNodes.length).toBe(1);
1459 + expect(container.childNodes[0]).toBe(primaryChild);
1460 + expect(primaryChild.textContent).toBe('Content 1');
1461 + expect(primaryChild.style.color).toBe('red');
1462 + expect(primaryChild.style.display).toBe('');
1463 +
1464 + // Perform a hot update.
1465 + patch(() => {
1466 + function Hello({children}) {
1467 + const [val, setVal] = React.useState(0);
1468 + return (
1469 + <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
1470 + {children} {val}
1471 + </p>
1472 + );
1473 + }
1474 + __register__(Hello, 'Hello');
1475 + });
1476 + expect(container.childNodes.length).toBe(1);
1477 + expect(container.childNodes[0]).toBe(primaryChild);
1478 + expect(primaryChild.textContent).toBe('Content 1');
1479 + expect(primaryChild.style.color).toBe('orange');
1480 + expect(primaryChild.style.display).toBe('');
1481 + }
1482 + });
1483 +
1484 it('does not re-render ancestor components unnecessarily during a hot update', () => {
1485 if (__DEV__) {
1486 let appRenders = 0;
@@ -963,6 +1549,96 @@ describe('ReactFresh', () => {
1549 }
1550 });
1551
1552 + it('does not leak state between components', () => {
1553 + if (__DEV__) {
1554 + const AppV1 = render(
1555 + () => {
1556 + function Hello1() {
1557 + const [val, setVal] = React.useState(0);
1558 + return (
1559 + <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
1560 + {val}
1561 + </p>
1562 + );
1563 + }
1564 + __register__(Hello1, 'Hello1');
1565 + function Hello2() {
1566 + const [val, setVal] = React.useState(0);
1567 + return (
1568 + <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
1569 + {val}
1570 + </p>
1571 + );
1572 + }
1573 + __register__(Hello2, 'Hello2');
1574 + function App({cond}) {
1575 + return cond ? <Hello1 /> : <Hello2 />;
1576 + }
1577 + __register__(App, 'App');
1578 + return App;
1579 + },
1580 + {cond: false},
1581 + );
1582 +
1583 + // Bump the state before patching.
1584 + const el = container.firstChild;
1585 + expect(el.textContent).toBe('0');
1586 + expect(el.style.color).toBe('blue');
1587 + act(() => {
1588 + el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
1589 + });
1590 + expect(el.textContent).toBe('1');
1591 +
1592 + // Switch the condition, flipping inner content.
1593 + // This should reset the state.
1594 + render(() => AppV1, {cond: true});
1595 + const el2 = container.firstChild;
1596 + expect(el2).not.toBe(el);
1597 + expect(el2.textContent).toBe('0');
1598 + expect(el2.style.color).toBe('blue');
1599 +
1600 + // Bump it again.
1601 + act(() => {
1602 + el2.dispatchEvent(new MouseEvent('click', {bubbles: true}));
1603 + });
1604 + expect(el2.textContent).toBe('1');
1605 +
1606 + // Perform a hot update for both inner components.
1607 + patch(() => {
1608 + function Hello1() {
1609 + const [val, setVal] = React.useState(0);
1610 + return (
1611 + <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
1612 + {val}
1613 + </p>
1614 + );
1615 + }
1616 + __register__(Hello1, 'Hello1');
1617 + function Hello2() {
1618 + const [val, setVal] = React.useState(0);
1619 + return (
1620 + <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
1621 + {val}
1622 + </p>
1623 + );
1624 + }
1625 + __register__(Hello2, 'Hello2');
1626 + });
1627 +
1628 + // Assert the state was preserved but color changed.
1629 + expect(container.firstChild).toBe(el2);
1630 + expect(el2.textContent).toBe('1');
1631 + expect(el2.style.color).toBe('red');
1632 +
1633 + // Flip the condition again.
1634 + render(() => AppV1, {cond: false});
1635 + const el3 = container.firstChild;
1636 + expect(el3).not.toBe(el2);
1637 + expect(el3.textContent).toBe('0');
1638 + expect(el3.style.color).toBe('red');
1639 + }
1640 + });
1641 +
1642 it('can force remount by changing signature', () => {
1643 if (__DEV__) {
1644 let HelloV1 = render(() => {
packages/react-reconciler/src/ReactFiberBeginWork.js
+8 -3
@@ -1030,9 +1030,6 @@ function mountLazyComponent(
1030 // Cancel and resume right after we know the tag.
1031 cancelWorkTimer(workInProgress);
1032 let Component = readLazyComponentType(elementType);
1033 - if (__DEV__) {
1034 - // TODO: resolve type for hot reloading.
1035 - }
1033 // Store the unwrapped component in the type.
1034 workInProgress.type = Component;
1035 const resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component));
@@ -1043,6 +1040,9 @@ function mountLazyComponent(
1040 case FunctionComponent: {
1041 if (__DEV__) {
1042 validateFunctionComponentInDev(workInProgress, Component);
1043 + workInProgress.type = Component = resolveFunctionForHotReloading(
1044 + Component,
1045 + );
1046 }
1047 child = updateFunctionComponent(
1048 null,
@@ -1064,6 +1064,11 @@ function mountLazyComponent(
1064 break;
1065 }
1066 case ForwardRef: {
1067 + if (__DEV__) {
1068 + workInProgress.type = Component = resolveFunctionForHotReloading(
1069 + Component,
1070 + );
1071 + }
1072 child = updateForwardRef(
1073 null,
1074 workInProgress,