[Fresh] Don't traverse remounted trees (#15685)
* Don't traverse children when hot reloading needs a remount If we're gonna remount that tree anyway, there is no use in traversing its children beforehand. * Add a test verifying hot reload batches updates Otherwise there is a risk of it being super slow due to cascades.
Dan Abramov committed
May 20, 2019 at 14:55 UTC
ec38def44f2ff696ec0b73c212265fd2324bcdaf
2 files changed
+53
-7
packages/react-dom/src/__tests__/ReactFresh-test.internal.js
+41
@@ -1549,6 +1549,47 @@ describe('ReactFresh', () => {
1549
}
1550
});
1551
1552
+ it('batches re-renders during a hot update', () => {
1553
+ if (__DEV__) {
1554
+ let helloRenders = 0;
1555
+
1556
+ render(() => {
1557
+ function Hello({children}) {
1558
+ helloRenders++;
1559
+ return <div>X{children}X</div>;
1560
+ }
1561
+ __register__(Hello, 'Hello');
1562
+
1563
+ function App() {
1564
+ return (
1565
+ <Hello>
1566
+ <Hello>
1567
+ <Hello />
1568
+ </Hello>
1569
+ <Hello>
1570
+ <Hello />
1571
+ </Hello>
1572
+ </Hello>
1573
+ );
1574
+ }
1575
+ return App;
1576
+ });
1577
+ expect(helloRenders).toBe(5);
1578
+ expect(container.textContent).toBe('XXXXXXXXXX');
1579
+ helloRenders = 0;
1580
+
1581
+ patch(() => {
1582
+ function Hello({children}) {
1583
+ helloRenders++;
1584
+ return <div>O{children}O</div>;
1585
+ }
1586
+ __register__(Hello, 'Hello');
1587
+ });
1588
+ expect(helloRenders).toBe(5);
1589
+ expect(container.textContent).toBe('OOOOOOOOOO');
1590
+ }
1591
+ });
1592
+
1593
it('does not leak state between components', () => {
1594
if (__DEV__) {
1595
const AppV1 = render(
packages/react-reconciler/src/ReactFiberHotReloading.js
+12
-7
@@ -224,29 +224,34 @@ function scheduleFibersWithFamiliesRecursively(
224
throw new Error('Expected familiesByType to be set during hot reload.');
225
}
226
227
+ let needsRender = false;
228
+ let needsRemount = false;
229
if (candidateType !== null) {
230
const family = familiesByType.get(candidateType);
231
if (family !== undefined) {
232
if (staleFamilies.has(family)) {
231
- fiber._debugNeedsRemount = true;
232
- scheduleWork(fiber, Sync);
233
+ needsRemount = true;
234
} else if (updatedFamilies.has(family)) {
234
- scheduleWork(fiber, Sync);
235
+ needsRender = true;
236
}
237
}
238
}
238
-
239
if (failedBoundaries !== null) {
240
if (
241
failedBoundaries.has(fiber) ||
242
(alternate !== null && failedBoundaries.has(alternate))
243
) {
244
- fiber._debugNeedsRemount = true;
245
- scheduleWork(fiber, Sync);
244
+ needsRemount = true;
245
}
246
}
247
249
- if (child !== null) {
248
+ if (needsRemount) {
249
+ fiber._debugNeedsRemount = true;
250
+ }
251
+ if (needsRemount || needsRender) {
252
+ scheduleWork(fiber, Sync);
253
+ }
254
+ if (child !== null && !needsRemount) {
255
scheduleFibersWithFamiliesRecursively(
256
child,
257
updatedFamilies,