Skip to content

Commit fd339b3

Browse files
committed
Display key from ReactComponentInfo and use it to handle reordered Virtual Instances
1 parent 900b206 commit fd339b3

File tree

2 files changed

+41
-25
lines changed

2 files changed

+41
-25
lines changed

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,7 +2439,7 @@ describe('Store', () => {
24392439
});
24402440

24412441
// @reactVersion > 18.2
2442-
it('can reorder keyed components', async () => {
2442+
it('can reorder keyed server components', async () => {
24432443
function ClientComponent({text}) {
24442444
return <div>{text}</div>;
24452445
}
@@ -2452,9 +2452,7 @@ describe('Store', () => {
24522452
name: 'ServerComponent',
24532453
env: 'Server',
24542454
owner: null,
2455-
// TODO: Ideally the debug info should include the "key" too to
2456-
// preserve the virtual identity of the server component when
2457-
// reordered. Atm only the children of it gets reparented.
2455+
key: key,
24582456
},
24592457
];
24602458
return ServerPromise;
@@ -2468,23 +2466,23 @@ describe('Store', () => {
24682466
expect(store).toMatchInlineSnapshot(`
24692467
[root]
24702468
▾ <App>
2471-
▾ <ServerComponent> [Server]
2469+
▾ <ServerComponent key="A"> [Server]
24722470
<ClientComponent key="A">
2473-
▾ <ServerComponent> [Server]
2471+
▾ <ServerComponent key="B"> [Server]
24742472
<ClientComponent key="B">
2475-
▾ <ServerComponent> [Server]
2473+
▾ <ServerComponent key="C"> [Server]
24762474
<ClientComponent key="C">
24772475
`);
24782476

24792477
await actAsync(() => render(<App initial={false} />));
24802478
expect(store).toMatchInlineSnapshot(`
24812479
[root]
24822480
▾ <App>
2483-
▾ <ServerComponent> [Server]
2481+
▾ <ServerComponent key="B"> [Server]
24842482
<ClientComponent key="B">
2485-
▾ <ServerComponent> [Server]
2483+
▾ <ServerComponent key="A"> [Server]
24862484
<ClientComponent key="A">
2487-
▾ <ServerComponent> [Server]
2485+
▾ <ServerComponent key="D"> [Server]
24882486
<ClientComponent key="D">
24892487
`);
24902488
});

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

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2220,9 +2220,12 @@ export function attach(
22202220

22212221
const isProfilingSupported = false; // TODO: Support Tree Base Duration Based on Children.
22222222

2223-
const key = null; // TODO: Track keys on ReactComponentInfo;
2224-
const env = instance.data.env;
2225-
let displayName = instance.data.name || '';
2223+
const componentInfo = instance.data;
2224+
2225+
const key =
2226+
typeof componentInfo.key === 'string' ? componentInfo.key : null;
2227+
const env = componentInfo.env;
2228+
let displayName = componentInfo.name || '';
22262229
if (typeof env === 'string') {
22272230
// We model environment as an HoC name for now.
22282231
displayName = env + '(' + displayName + ')';
@@ -2855,19 +2858,32 @@ export function attach(
28552858
);
28562859
}
28572860
}
2858-
const firstRemainingChild = remainingReconcilingChildren;
2861+
// TODO: Find the best matching existing child based on the key if defined.
2862+
2863+
let bestMatch = remainingReconcilingChildren;
2864+
if (componentInfo.key != null) {
2865+
// If there is a key try to find a matching key in the set.
2866+
bestMatch = remainingReconcilingChildren;
2867+
while (bestMatch !== null) {
2868+
if (bestMatch.kind === VIRTUAL_INSTANCE && bestMatch.data.key === componentInfo.key) {
2869+
break;
2870+
}
2871+
bestMatch = bestMatch.nextSibling;
2872+
}
2873+
}
28592874
if (
2860-
firstRemainingChild !== null &&
2861-
firstRemainingChild.kind === VIRTUAL_INSTANCE &&
2862-
firstRemainingChild.data.name === componentInfo.name &&
2863-
firstRemainingChild.data.env === componentInfo.env
2875+
bestMatch !== null &&
2876+
bestMatch.kind === VIRTUAL_INSTANCE &&
2877+
bestMatch.data.name === componentInfo.name &&
2878+
bestMatch.data.env === componentInfo.env &&
2879+
bestMatch.data.key === componentInfo.key
28642880
) {
28652881
// If the previous children had a virtual instance in the same slot
28662882
// with the same name, then we claim it and reuse it for this update.
28672883
// Update it with the latest entry.
2868-
firstRemainingChild.data = componentInfo;
2869-
moveChild(firstRemainingChild);
2870-
previousVirtualInstance = firstRemainingChild;
2884+
bestMatch.data = componentInfo;
2885+
moveChild(bestMatch);
2886+
previousVirtualInstance = bestMatch;
28712887
previousVirtualInstanceWasMount = false;
28722888
} else {
28732889
// Otherwise we create a new instance.
@@ -4321,11 +4337,13 @@ export function attach(
43214337
): InspectedElement | null {
43224338
const canViewSource = false;
43234339

4324-
const key = null; // TODO: Track keys on ReactComponentInfo;
4340+
const componentInfo = virtualInstance.data;
4341+
const key =
4342+
typeof componentInfo.key === 'string' ? componentInfo.key : null;
43254343
const props = null; // TODO: Track props on ReactComponentInfo;
43264344

4327-
const env = virtualInstance.data.env;
4328-
let displayName = virtualInstance.data.name || '';
4345+
const env = componentInfo.env;
4346+
let displayName = componentInfo.name || '';
43294347
if (typeof env === 'string') {
43304348
// We model environment as an HoC name for now.
43314349
displayName = env + '(' + displayName + ')';
@@ -4384,7 +4402,7 @@ export function attach(
43844402
// Does the component have legacy context attached to it.
43854403
hasLegacyContext: false,
43864404

4387-
key: key != null ? key : null,
4405+
key: key,
43884406

43894407
displayName: displayName,
43904408
type: ElementTypeVirtual,

0 commit comments

Comments
 (0)