Skip to content

Commit c44fbf4

Browse files
authored
[DevTools] Fix instrumentation error when reconciling promise-as-a-child (#34587)
1 parent 8ad773b commit c44fbf4

File tree

2 files changed

+55
-7
lines changed

2 files changed

+55
-7
lines changed

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3107,4 +3107,45 @@ describe('Store', () => {
31073107
await actAsync(() => render(<span />));
31083108
expect(store).toMatchInlineSnapshot(`[root]`);
31093109
});
3110+
3111+
// @reactVersion >= 19.0
3112+
it('should reconcile promise-as-a-child', async () => {
3113+
function Component({children}) {
3114+
return <div>{children}</div>;
3115+
}
3116+
3117+
await actAsync(() =>
3118+
render(
3119+
<React.Suspense>
3120+
{Promise.resolve(<Component key="A">A</Component>)}
3121+
</React.Suspense>,
3122+
),
3123+
);
3124+
expect(store).toMatchInlineSnapshot(`
3125+
[root]
3126+
▾ <Suspense>
3127+
<Component key="A">
3128+
[suspense-root] rects={[{x:1,y:2,width:1,height:1}]}
3129+
<Suspense name="Unknown" rects={[{x:1,y:2,width:1,height:1}]}>
3130+
`);
3131+
3132+
await actAsync(() =>
3133+
render(
3134+
<React.Suspense>
3135+
{Promise.resolve(<Component key="not-A">not A</Component>)}
3136+
</React.Suspense>,
3137+
),
3138+
);
3139+
3140+
expect(store).toMatchInlineSnapshot(`
3141+
[root]
3142+
▾ <Suspense>
3143+
<Component key="not-A">
3144+
[suspense-root] rects={[{x:1,y:2,width:5,height:1}]}
3145+
<Suspense name="Unknown" rects={[{x:1,y:2,width:5,height:1}]}>
3146+
`);
3147+
3148+
await actAsync(() => render(null));
3149+
expect(store).toMatchInlineSnapshot(``);
3150+
});
31103151
});

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

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2886,9 +2886,16 @@ export function attach(
28862886
previousSuspendedBy: null | Array<ReactAsyncInfo>,
28872887
parentSuspenseNode: null | SuspenseNode,
28882888
): void {
2889-
// Remove any async info from the parent, if they were in the previous set but
2889+
// Remove any async info if they were in the previous set but
28902890
// is no longer in the new set.
2891-
if (previousSuspendedBy !== null && parentSuspenseNode !== null) {
2891+
// If we just reconciled a SuspenseNode, we need to remove from that node instead of the parent.
2892+
// This is different from inserting because inserting is done during reconiliation
2893+
// whereas removal is done after we're done reconciling.
2894+
const suspenseNode =
2895+
instance.suspenseNode === null
2896+
? parentSuspenseNode
2897+
: instance.suspenseNode;
2898+
if (previousSuspendedBy !== null && suspenseNode !== null) {
28922899
const nextSuspendedBy = instance.suspendedBy;
28932900
for (let i = 0; i < previousSuspendedBy.length; i++) {
28942901
const asyncInfo = previousSuspendedBy[i];
@@ -2901,7 +2908,7 @@ export function attach(
29012908
// This IO entry is no longer blocking the current tree.
29022909
// Let's remove it from the parent SuspenseNode.
29032910
const ioInfo = asyncInfo.awaited;
2904-
const suspendedBySet = parentSuspenseNode.suspendedBy.get(ioInfo);
2911+
const suspendedBySet = suspenseNode.suspendedBy.get(ioInfo);
29052912
29062913
if (
29072914
suspendedBySet === undefined ||
@@ -2928,16 +2935,16 @@ export function attach(
29282935
}
29292936
}
29302937
if (suspendedBySet !== undefined && suspendedBySet.size === 0) {
2931-
parentSuspenseNode.suspendedBy.delete(asyncInfo.awaited);
2938+
suspenseNode.suspendedBy.delete(asyncInfo.awaited);
29322939
}
29332940
if (
2934-
parentSuspenseNode.hasUniqueSuspenders &&
2935-
!ioExistsInSuspenseAncestor(parentSuspenseNode, ioInfo)
2941+
suspenseNode.hasUniqueSuspenders &&
2942+
!ioExistsInSuspenseAncestor(suspenseNode, ioInfo)
29362943
) {
29372944
// This entry wasn't in any ancestor and is no longer in this suspense boundary.
29382945
// This means that a child might now be the unique suspender for this IO.
29392946
// Search the child boundaries to see if we can reveal any of them.
2940-
unblockSuspendedBy(parentSuspenseNode, ioInfo);
2947+
unblockSuspendedBy(suspenseNode, ioInfo);
29412948
}
29422949
}
29432950
}

0 commit comments

Comments
 (0)