@samitouri / QOS-React-2 / commits / cf6e502ed2

Hot reloading: Avoid stack overflow on wide trees (#34145)

Every sibling added to the stack here. Not sure this needs to be recursive at all but certainly for siblings this can just be a loop.

Sophie Alpert committed Aug 9, 2025 at 08:02 UTC cf6e502ed23ab3357e58965789324ddfa0e12821
1 file changed +59 -59
packages/react-reconciler/src/ReactFiberHotReloading.js
+59 -59
@@ -261,74 +261,74 @@ function scheduleFibersWithFamiliesRecursively(
261 staleFamilies: Set<Family>,
262 ): void {
263 if (__DEV__) {
264 - const {alternate, child, sibling, tag, type} = fiber;
264 + do {
265 + const {alternate, child, sibling, tag, type} = fiber;
266
266 - let candidateType = null;
267 - switch (tag) {
268 - case FunctionComponent:
269 - case SimpleMemoComponent:
270 - case ClassComponent:
271 - candidateType = type;
272 - break;
273 - case ForwardRef:
274 - candidateType = type.render;
275 - break;
276 - default:
277 - break;
278 - }
267 + let candidateType = null;
268 + switch (tag) {
269 + case FunctionComponent:
270 + case SimpleMemoComponent:
271 + case ClassComponent:
272 + candidateType = type;
273 + break;
274 + case ForwardRef:
275 + candidateType = type.render;
276 + break;
277 + default:
278 + break;
279 + }
280
280 - if (resolveFamily === null) {
281 - throw new Error('Expected resolveFamily to be set during hot reload.');
282 - }
281 + if (resolveFamily === null) {
282 + throw new Error('Expected resolveFamily to be set during hot reload.');
283 + }
284
284 - let needsRender = false;
285 - let needsRemount = false;
286 - if (candidateType !== null) {
287 - const family = resolveFamily(candidateType);
288 - if (family !== undefined) {
289 - if (staleFamilies.has(family)) {
290 - needsRemount = true;
291 - } else if (updatedFamilies.has(family)) {
292 - if (tag === ClassComponent) {
285 + let needsRender = false;
286 + let needsRemount = false;
287 + if (candidateType !== null) {
288 + const family = resolveFamily(candidateType);
289 + if (family !== undefined) {
290 + if (staleFamilies.has(family)) {
291 needsRemount = true;
294 - } else {
295 - needsRender = true;
292 + } else if (updatedFamilies.has(family)) {
293 + if (tag === ClassComponent) {
294 + needsRemount = true;
295 + } else {
296 + needsRender = true;
297 + }
298 }
299 }
300 }
299 - }
300 - if (failedBoundaries !== null) {
301 - if (
302 - failedBoundaries.has(fiber) ||
303 - // $FlowFixMe[incompatible-use] found when upgrading Flow
304 - (alternate !== null && failedBoundaries.has(alternate))
305 - ) {
306 - needsRemount = true;
301 + if (failedBoundaries !== null) {
302 + if (
303 + failedBoundaries.has(fiber) ||
304 + // $FlowFixMe[incompatible-use] found when upgrading Flow
305 + (alternate !== null && failedBoundaries.has(alternate))
306 + ) {
307 + needsRemount = true;
308 + }
309 }
308 - }
310
310 - if (needsRemount) {
311 - fiber._debugNeedsRemount = true;
312 - }
313 - if (needsRemount || needsRender) {
314 - const root = enqueueConcurrentRenderForLane(fiber, SyncLane);
315 - if (root !== null) {
316 - scheduleUpdateOnFiber(root, fiber, SyncLane);
311 + if (needsRemount) {
312 + fiber._debugNeedsRemount = true;
313 }
318 - }
319 - if (child !== null && !needsRemount) {
320 - scheduleFibersWithFamiliesRecursively(
321 - child,
322 - updatedFamilies,
323 - staleFamilies,
324 - );
325 - }
326 - if (sibling !== null) {
327 - scheduleFibersWithFamiliesRecursively(
328 - sibling,
329 - updatedFamilies,
330 - staleFamilies,
331 - );
332 - }
314 + if (needsRemount || needsRender) {
315 + const root = enqueueConcurrentRenderForLane(fiber, SyncLane);
316 + if (root !== null) {
317 + scheduleUpdateOnFiber(root, fiber, SyncLane);
318 + }
319 + }
320 + if (child !== null && !needsRemount) {
321 + scheduleFibersWithFamiliesRecursively(
322 + child,
323 + updatedFamilies,
324 + staleFamilies,
325 + );
326 + }
327 +
328 + if (sibling === null) {
329 + break;
330 + }
331 + fiber = sibling;
332 + } while (true);
333 }
334 }