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.
Brian Vaughn committed
Jan 21, 2022 at 11:05 UTC
13036bfbc8ecbcf4451adb7bde397f438caa8607
2 files changed
+33
-5
packages/react-devtools-shared/src/__tests__/profilerStore-test.js
+20
@@ -221,4 +221,24 @@ describe('ProfilerStore', () => {
221
expect(data.commitData).toHaveLength(1);
222
expect(data.operations).toHaveLength(1);
223
});
224
+
225
+ it('should not throw while initializing context values for Fibers within a not-yet-mounted subtree', () => {
226
+ const promise = new Promise(resolve => {});
227
+ const SuspendingView = () => {
228
+ throw promise;
229
+ };
230
+
231
+ const App = () => {
232
+ return (
233
+ <React.Suspense fallback="Fallback">
234
+ <SuspendingView />
235
+ </React.Suspense>
236
+ );
237
+ };
238
+
239
+ const container = document.createElement('div');
240
+
241
+ utils.act(() => legacyRender(<App />, container));
242
+ utils.act(() => store.profilerStore.startProfiling());
243
+ });
244
});
packages/react-devtools-shared/src/backend/renderer.js
+13
-5
@@ -1347,11 +1347,19 @@ export function attach(
1347
// Fibers only store the current context value,
1348
// so we need to track them separately in order to determine changed keys.
1349
function crawlToInitializeContextsMap(fiber: Fiber) {
1350
- updateContextsForFiber(fiber);
1351
- let current = fiber.child;
1352
- while (current !== null) {
1353
- crawlToInitializeContextsMap(current);
1354
- current = current.sibling;
1350
+ const id = getFiberIDUnsafe(fiber);
1351
+
1352
+ // Not all Fibers in the subtree have mounted yet.
1353
+ // For example, Offscreen (hidden) or Suspense (suspended) subtrees won't yet be tracked.
1354
+ // We can safely skip these subtrees.
1355
+ if (id !== null) {
1356
+ updateContextsForFiber(fiber);
1357
+
1358
+ let current = fiber.child;
1359
+ while (current !== null) {
1360
+ crawlToInitializeContextsMap(current);
1361
+ current = current.sibling;
1362
+ }
1363
}
1364
}
1365