Skip to content

Commit ec38def

Browse files
authored
[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.
1 parent 5731e52 commit ec38def

2 files changed

Lines changed: 53 additions & 7 deletions

File tree

packages/react-dom/src/__tests__/ReactFresh-test.internal.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,6 +1549,47 @@ describe('ReactFresh', () => {
15491549
}
15501550
});
15511551

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+
15521593
it('does not leak state between components', () => {
15531594
if (__DEV__) {
15541595
const AppV1 = render(

packages/react-reconciler/src/ReactFiberHotReloading.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -224,29 +224,34 @@ function scheduleFibersWithFamiliesRecursively(
224224
throw new Error('Expected familiesByType to be set during hot reload.');
225225
}
226226

227+
let needsRender = false;
228+
let needsRemount = false;
227229
if (candidateType !== null) {
228230
const family = familiesByType.get(candidateType);
229231
if (family !== undefined) {
230232
if (staleFamilies.has(family)) {
231-
fiber._debugNeedsRemount = true;
232-
scheduleWork(fiber, Sync);
233+
needsRemount = true;
233234
} else if (updatedFamilies.has(family)) {
234-
scheduleWork(fiber, Sync);
235+
needsRender = true;
235236
}
236237
}
237238
}
238-
239239
if (failedBoundaries !== null) {
240240
if (
241241
failedBoundaries.has(fiber) ||
242242
(alternate !== null && failedBoundaries.has(alternate))
243243
) {
244-
fiber._debugNeedsRemount = true;
245-
scheduleWork(fiber, Sync);
244+
needsRemount = true;
246245
}
247246
}
248247

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) {
250255
scheduleFibersWithFamiliesRecursively(
251256
child,
252257
updatedFamilies,

0 commit comments

Comments
 (0)