[DevTools] Stop mounting empty roots (#34467)
Sebastian "Sebbie" Silbermann committed
Sep 11, 2025 at 20:00 UTC
a9ad64c8524eb7a9af6753baa715a41909552fa6
2 files changed
+24
-26
packages/react-devtools-shared/src/__tests__/store-test.js
+4
-1
@@ -2489,7 +2489,7 @@ describe('Store', () => {
2489
withErrorsOrWarningsIgnored(['test-only:'], async () => {
2490
await act(() => render(<React.Fragment />));
2491
});
2492
- expect(store).toMatchInlineSnapshot(`[root]`);
2492
+ expect(store).toMatchInlineSnapshot(``);
2493
expect(store.componentWithErrorCount).toBe(0);
2494
expect(store.componentWithWarningCount).toBe(0);
2495
});
@@ -3083,6 +3083,9 @@ describe('Store', () => {
3083
3084
it('should handle an empty root', async () => {
3085
await actAsync(() => render(null));
3086
+ expect(store).toMatchInlineSnapshot(``);
3087
+
3088
+ await actAsync(() => render(<span />));
3089
expect(store).toMatchInlineSnapshot(`[root]`);
3090
});
3091
});
packages/react-devtools-shared/src/backend/fiber/renderer.js
+20
-25
@@ -5322,12 +5322,12 @@ export function attach(
5322
root: FiberRoot,
5323
priorityLevel: void | number,
5324
) {
5325
- const current = root.current;
5325
+ const nextFiber = root.current;
5326
5327
let prevFiber: null | Fiber = null;
5328
let rootInstance = rootToFiberInstanceMap.get(root);
5329
if (!rootInstance) {
5330
- rootInstance = createFiberInstance(current);
5330
+ rootInstance = createFiberInstance(nextFiber);
5331
rootToFiberInstanceMap.set(root, rootInstance);
5332
idToDevToolsInstanceMap.set(rootInstance.id, rootInstance);
5333
} else {
@@ -5366,30 +5366,25 @@ export function attach(
5366
};
5367
}
5368
5369
- if (prevFiber !== null) {
5370
- // TODO: relying on this seems a bit fishy.
5371
- const wasMounted =
5372
- prevFiber.memoizedState != null &&
5373
- prevFiber.memoizedState.element != null;
5374
- const isMounted =
5375
- current.memoizedState != null && current.memoizedState.element != null;
5376
- if (!wasMounted && isMounted) {
5377
- // Mount a new root.
5378
- setRootPseudoKey(currentRoot.id, current);
5379
- mountFiberRecursively(current, false);
5380
- } else if (wasMounted && isMounted) {
5381
- // Update an existing root.
5382
- updateFiberRecursively(rootInstance, current, prevFiber, false);
5383
- } else if (wasMounted && !isMounted) {
5384
- // Unmount an existing root.
5385
- unmountInstanceRecursively(rootInstance);
5386
- removeRootPseudoKey(currentRoot.id);
5387
- rootToFiberInstanceMap.delete(root);
5388
- }
5389
- } else {
5369
+ const nextIsMounted = nextFiber.child !== null;
5370
+ const prevWasMounted = prevFiber !== null && prevFiber.child !== null;
5371
+ if (!prevWasMounted && nextIsMounted) {
5372
// Mount a new root.
5391
- setRootPseudoKey(currentRoot.id, current);
5392
- mountFiberRecursively(current, false);
5373
+ setRootPseudoKey(currentRoot.id, nextFiber);
5374
+ mountFiberRecursively(nextFiber, false);
5375
+ } else if (prevWasMounted && nextIsMounted) {
5376
+ if (prevFiber === null) {
5377
+ throw new Error(
5378
+ 'Expected a previous Fiber when updating an existing root.',
5379
+ );
5380
+ }
5381
+ // Update an existing root.
5382
+ updateFiberRecursively(rootInstance, nextFiber, prevFiber, false);
5383
+ } else if (prevWasMounted && !nextIsMounted) {
5384
+ // Unmount an existing root.
5385
+ unmountInstanceRecursively(rootInstance);
5386
+ removeRootPseudoKey(currentRoot.id);
5387
+ rootToFiberInstanceMap.delete(root);
5388
}
5389
5390
if (isProfiling && isProfilingSupported) {