[DevTools] Use same Suspense naming heuristics when reconnecting (#34898)

This commit is contained in:
Sebastian "Sebbie" Silbermann 2025-10-18 12:54:05 +02:00 committed by GitHub
parent 3a669170e9
commit 40c7a7f6ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 64 additions and 16 deletions

View File

@ -3243,4 +3243,61 @@ describe('Store', () => {
<Suspense name="inner-suspense" rects={[{x:1,y:2,width:15,height:1}]}>
`);
});
// @reactVersion >= 19.0
it('guesses a Suspense name based on the owner', async () => {
let resolve;
const promise = new Promise(_resolve => {
resolve = _resolve;
});
function Inner() {
return (
<React.Suspense fallback={<p>Loading inner</p>}>
<p>{promise}</p>
</React.Suspense>
);
}
function Outer({children}) {
return (
<React.Suspense fallback={<p>Loading outer</p>}>
<p>{promise}</p>
{children}
</React.Suspense>
);
}
await actAsync(() => {
render(
<Outer>
<Inner />
</Outer>,
);
});
expect(store).toMatchInlineSnapshot(`
[root]
<Outer>
<Suspense>
[suspense-root] rects={[{x:1,y:2,width:13,height:1}]}
<Suspense name="Outer" rects={null}>
`);
console.log('...........................');
await actAsync(() => {
resolve('loaded');
});
expect(store).toMatchInlineSnapshot(`
[root]
<Outer>
<Suspense>
<Inner>
<Suspense>
[suspense-root] rects={[{x:1,y:2,width:6,height:1}, {x:1,y:2,width:6,height:1}]}
<Suspense name="Outer" rects={[{x:1,y:2,width:6,height:1}, {x:1,y:2,width:6,height:1}]}>
<Suspense name="Inner" rects={[{x:1,y:2,width:6,height:1}]}>
`);
});
});

View File

@ -2664,7 +2664,7 @@ export function attach(
const fiber = fiberInstance.data;
const props = fiber.memoizedProps;
// TODO: Compute a fallback name based on Owner, key etc.
// The frontend will guess a name based on heuristics (e.g. owner) if no explicit name is given.
const name =
fiber.tag !== SuspenseComponent || props === null
? null

View File

@ -1646,10 +1646,6 @@ export default class Store extends EventEmitter<{
parentSuspense.children.push(id);
}
if (name === null) {
name = 'Unknown';
}
this._idToSuspense.set(id, {
id,
parentID,
@ -2170,13 +2166,12 @@ export default class Store extends EventEmitter<{
throw error;
}
_guessSuspenseName(element: Element): string {
_guessSuspenseName(element: Element): string | null {
const owner = this._idToElement.get(element.ownerID);
let name = 'Unknown';
if (owner !== undefined && owner.displayName !== null) {
name = owner.displayName;
return owner.displayName;
}
return name;
return null;
}
}

View File

@ -63,11 +63,7 @@ function printRects(rects: SuspenseNode['rects']): string {
}
function printSuspense(suspense: SuspenseNode): string {
let name = '';
if (suspense.name !== null) {
name = ` name="${suspense.name}"`;
}
const name = ` name="${suspense.name || 'Unknown'}"`;
const printedRects = printRects(suspense.rects);
return `<Suspense${name}${printedRects}>`;

View File

@ -72,7 +72,7 @@ export default function SuspenseBreadcrumbs(): React$Node {
className={styles.SuspenseBreadcrumbsButton}
onClick={handleClick.bind(null, id)}
type="button">
{node === null ? 'Unknown' : node.name}
{node === null ? 'Unknown' : node.name || 'Unknown'}
</button>
</li>
);

View File

@ -196,7 +196,7 @@ function SuspenseRects({
onPointerOver={handlePointerOver}
onPointerLeave={handlePointerLeave}
// Reach-UI tooltip will go out of bounds of parent scroll container.
title={suspense.name}
title={suspense.name || 'Unknown'}
/>
);
})}