Skip to content

Commit dd3c9d4

Browse files
committed
[DevTools] Attach async info in filtered fallback to parent of Suspense
1 parent c88a2bf commit dd3c9d4

File tree

2 files changed

+28
-5
lines changed

2 files changed

+28
-5
lines changed

packages/react-devtools-shared/src/__tests__/store-test.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3186,12 +3186,11 @@ describe('Store', () => {
31863186
<Suspense name="main" rects={null}>
31873187
`);
31883188

3189-
await expect(actAsync(() => resolveContent('content'))).rejects.toThrow(
3190-
'We are cleaning up async info that was not on the parent Suspense boundary. This is a bug in React.',
3191-
);
3189+
await actAsync(() => resolveContent('content'));
31923190
expect(store).toMatchInlineSnapshot(`
31933191
[root]
3194-
<Suspense name="main">
3192+
▾ <Suspense name="main">
3193+
<Component>
31953194
[suspense-root] rects={null}
31963195
<Suspense name="main" rects={null}>
31973196
`);

packages/react-devtools-shared/src/backend/fiber/renderer.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2992,6 +2992,30 @@ export function attach(
29922992
) {
29932993
parentInstance = parentInstance.parent;
29942994
}
2995+
if (parentInstance.kind === FIBER_INSTANCE) {
2996+
const fiber = parentInstance.data;
2997+
2998+
if (
2999+
fiber.tag === SuspenseComponent &&
3000+
parentInstance !== parentSuspenseNode.instance
3001+
) {
3002+
// We're about to attach async info to a Suspense boundary we're not
3003+
// actually considering the parent Suspense boundary for this async info.
3004+
// We must have not found a suitable Fiber inside the fallback (e.g. due to filtering).
3005+
// Use the parent of this instance instead since we treat async info
3006+
// attached to a Suspense boundary as that async info triggering the
3007+
// fallback of that boundary.
3008+
const parent = parentInstance.parent;
3009+
if (parent === null) {
3010+
// This shouldn't happen. Any <Suspense> would have at least have the
3011+
// host root as the parent which can't have a fallback.
3012+
throw new Error(
3013+
'Did not find a suitable instance for this async info. This is a bug in React.',
3014+
);
3015+
}
3016+
parentInstance = parent;
3017+
}
3018+
}
29953019
29963020
const suspenseNodeSuspendedBy = parentSuspenseNode.suspendedBy;
29973021
const ioInfo = asyncInfo.awaited;
@@ -5255,9 +5279,9 @@ export function attach(
52555279
// It might even result in a bad user experience for e.g. node selection in the Elements panel.
52565280
// The easiest fix is to strip out the intermediate Fragment fibers,
52575281
// so the Elements panel and Profiler don't need to special case them.
5258-
// Suspense components only have a non-null memoizedState if they're timed-out.
52595282
const isLegacySuspense =
52605283
nextFiber.tag === SuspenseComponent && OffscreenComponent === -1;
5284+
// Suspense components only have a non-null memoizedState if they're timed-out.
52615285
const prevDidTimeout =
52625286
isLegacySuspense && prevFiber.memoizedState !== null;
52635287
const nextDidTimeOut =

0 commit comments

Comments
 (0)