@samitouri / QOS-React / commits / 03a96c75db

[DevTools] Record Suspense node for roots in legacy renderers (#34516)

Sebastian "Sebbie" Silbermann committed Sep 18, 2025 at 18:50 UTC 03a96c75db12eeac36b4d5d88c13e3a12d46efe1
2 files changed +23 -3
packages/react-devtools-shared/src/backend/legacy/renderer.js
+21 -1
@@ -34,6 +34,8 @@ import {
34 TREE_OPERATION_ADD,
35 TREE_OPERATION_REMOVE,
36 TREE_OPERATION_REORDER_CHILDREN,
37 + SUSPENSE_TREE_OPERATION_ADD,
38 + SUSPENSE_TREE_OPERATION_REMOVE,
39 UNKNOWN_SUSPENDERS_NONE,
40 } from '../../constants';
41 import {decorateMany, forceUpdate, restoreMany} from './utils';
@@ -411,6 +413,13 @@ export function attach(
413 pushOperation(0); // StrictMode supported?
414 pushOperation(hasOwnerMetadata ? 1 : 0);
415 pushOperation(supportsTogglingSuspense ? 1 : 0);
416 +
417 + pushOperation(SUSPENSE_TREE_OPERATION_ADD);
418 + pushOperation(id);
419 + pushOperation(parentID);
420 + pushOperation(getStringID(null)); // name
421 + // TODO: Measure rect of root
422 + pushOperation(-1);
423 } else {
424 const type = getElementType(internalInstance);
425 const {displayName, key} = getData(internalInstance);
@@ -449,7 +458,12 @@ export function attach(
458 }
459
460 function recordUnmount(internalInstance: InternalInstance, id: number) {
452 - pendingUnmountedIDs.push(id);
461 + const isRoot = parentIDStack.length === 0;
462 + if (isRoot) {
463 + pendingUnmountedRootID = id;
464 + } else {
465 + pendingUnmountedIDs.push(id);
466 + }
467 idToInternalInstanceMap.delete(id);
468 }
469
@@ -519,6 +533,8 @@ export function attach(
533 // All unmounts are batched in a single message.
534 // [TREE_OPERATION_REMOVE, removedIDLength, ...ids]
535 (numUnmountIDs > 0 ? 2 + numUnmountIDs : 0) +
536 + // [SUSPENSE_TREE_OPERATION_REMOVE, 1, pendingUnmountedRootID]
537 + (pendingUnmountedRootID === null ? 0 : 3) +
538 // Mount operations
539 pendingOperations.length,
540 );
@@ -555,6 +571,10 @@ export function attach(
571 if (pendingUnmountedRootID !== null) {
572 operations[i] = pendingUnmountedRootID;
573 i++;
574 +
575 + operations[i++] = SUSPENSE_TREE_OPERATION_REMOVE;
576 + operations[i++] = 1;
577 + operations[i++] = pendingUnmountedRootID;
578 }
579 }
580
packages/react-devtools-shared/src/devtools/store.js
+2 -2
@@ -895,11 +895,11 @@ export default class Store extends EventEmitter<{
895 if (root === null) {
896 return [];
897 }
898 - if (!this.supportsTogglingSuspense(root.id)) {
898 + if (!this.supportsTogglingSuspense(rootID)) {
899 return [];
900 }
901 const list: SuspenseNode['id'][] = [];
902 - const suspense = this.getSuspenseByID(root.id);
902 + const suspense = this.getSuspenseByID(rootID);
903 if (suspense !== null) {
904 const stack = [suspense];
905 while (stack.length > 0) {