From 13036bfbc8ecbcf4451adb7bde397f438caa8607 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Fri, 21 Jan 2022 11:05:49 -0500 Subject: [PATCH] DevTools should not crawl unmounted subtrees when profiling starts (#23162) Previously we crawled all subtrees, even not-yet-mounted ones, to initialize context values. This was not only unecessary, but it also caused an error to be thrown. This commit adds a test and fixes that behavior. --- .../src/__tests__/profilerStore-test.js | 20 +++++++++++++++++++ .../src/backend/renderer.js | 18 ++++++++++++----- 2 files changed, 33 insertions(+), 5 deletions(-) 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; + } } }