diff --git a/packages/react-devtools-shared/src/__tests__/profilerStore-test.js b/packages/react-devtools-shared/src/__tests__/profilerStore-test.js index 06ce6a9dc4c8f..7f553bed82e8b 100644 --- a/packages/react-devtools-shared/src/__tests__/profilerStore-test.js +++ b/packages/react-devtools-shared/src/__tests__/profilerStore-test.js @@ -221,4 +221,24 @@ describe('ProfilerStore', () => { expect(data.commitData).toHaveLength(1); expect(data.operations).toHaveLength(1); }); + + it('should not throw while initializing context values for Fibers within a not-yet-mounted subtree', () => { + const promise = new Promise(resolve => {}); + const SuspendingView = () => { + throw promise; + }; + + const App = () => { + return ( + + + + ); + }; + + const container = document.createElement('div'); + + utils.act(() => legacyRender(, container)); + utils.act(() => store.profilerStore.startProfiling()); + }); }); diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index 0f7b15cd019b9..9a60fe42376a2 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -1347,11 +1347,19 @@ export function attach( // Fibers only store the current context value, // so we need to track them separately in order to determine changed keys. function crawlToInitializeContextsMap(fiber: Fiber) { - updateContextsForFiber(fiber); - let current = fiber.child; - while (current !== null) { - crawlToInitializeContextsMap(current); - current = current.sibling; + const id = getFiberIDUnsafe(fiber); + + // Not all Fibers in the subtree have mounted yet. + // For example, Offscreen (hidden) or Suspense (suspended) subtrees won't yet be tracked. + // We can safely skip these subtrees. + if (id !== null) { + updateContextsForFiber(fiber); + + let current = fiber.child; + while (current !== null) { + crawlToInitializeContextsMap(current); + current = current.sibling; + } } }