diff --git a/packages/react-devtools-shared/src/__tests__/__snapshots__/profilingCache-test.js.snap b/packages/react-devtools-shared/src/__tests__/__snapshots__/profilingCache-test.js.snap index cc44049dd9a51..a47598e92d522 100644 --- a/packages/react-devtools-shared/src/__tests__/__snapshots__/profilingCache-test.js.snap +++ b/packages/react-devtools-shared/src/__tests__/__snapshots__/profilingCache-test.js.snap @@ -2191,6 +2191,65 @@ Object { } `; +exports[`ProfilingCache should handle unexpectedly shallow suspense trees: Empty Suspense node 1`] = ` +Object { + "commitData": Array [ + Object { + "changeDescriptions": Map {}, + "duration": 0, + "fiberActualDurations": Map { + 1 => 0, + 2 => 0, + }, + "fiberSelfDurations": Map { + 1 => 0, + 2 => 0, + }, + "interactionIDs": Array [], + "priorityLevel": "Normal", + "timestamp": 0, + }, + ], + "displayName": "Suspense", + "initialTreeBaseDurations": Map {}, + "interactionCommits": Map {}, + "interactions": Map {}, + "operations": Array [ + Array [ + 1, + 1, + 9, + 8, + 83, + 117, + 115, + 112, + 101, + 110, + 115, + 101, + 1, + 1, + 11, + 1, + 1, + 1, + 2, + 12, + 1, + 0, + 1, + 0, + 4, + 2, + 0, + ], + ], + "rootID": 1, + "snapshots": Map {}, +} +`; + exports[`ProfilingCache should properly detect changed hooks: CommitDetails commitIndex: 0 1`] = ` Object { "changeDescriptions": Map { diff --git a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js index 149449b1176d4..817becdc0d0eb 100644 --- a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js +++ b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js @@ -696,4 +696,24 @@ describe('ProfilingCache', () => { ), ); }); + + it('should handle unexpectedly shallow suspense trees', () => { + const container = document.createElement('div'); + + utils.act(() => store.profilerStore.startProfiling()); + utils.act(() => ReactDOM.render(, container)); + utils.act(() => store.profilerStore.stopProfiling()); + + function Validator({commitIndex, rootID}) { + const profilingDataForRoot = store.profilerStore.getDataForRoot(rootID); + expect(profilingDataForRoot).toMatchSnapshot('Empty Suspense node'); + return null; + } + + const rootID = store.roots[0]; + + utils.act(() => { + TestRenderer.create(); + }); + }); }); diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index 3a714ba5e1c0d..9e550da1dd8f0 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -1237,11 +1237,14 @@ export function attach( ); } } else { + let primaryChild: Fiber | null = null; const areSuspenseChildrenConditionallyWrapped = OffscreenComponent === -1; - const primaryChild: Fiber | null = areSuspenseChildrenConditionallyWrapped - ? fiber.child - : (fiber.child: any).child; + if (areSuspenseChildrenConditionallyWrapped) { + primaryChild = fiber.child; + } else if (fiber.child !== null) { + primaryChild = fiber.child.child; + } if (primaryChild !== null) { mountFiberRecursively( primaryChild, diff --git a/packages/react-devtools-shell/src/app/SuspenseTree/index.js b/packages/react-devtools-shell/src/app/SuspenseTree/index.js index d681092de9c3d..72fffe22b7833 100644 --- a/packages/react-devtools-shell/src/app/SuspenseTree/index.js +++ b/packages/react-devtools-shell/src/app/SuspenseTree/index.js @@ -25,10 +25,15 @@ function SuspenseTree() { + ); } +function EmptySuspense() { + return ; +} + function PrimaryFallbackTest({initialSuspend}) { const [suspend, setSuspend] = useState(initialSuspend); const fallbackStep = useTestSequence('fallback', Fallback1, Fallback2);