Skip to content

Commit 72c89f5

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

File tree

2 files changed

+44
-25
lines changed

2 files changed

+44
-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: 36 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,35 @@ 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 (
2869+
bestMatch.kind === VIRTUAL_INSTANCE &&
2870+
bestMatch.data.key === componentInfo.key
2871+
) {
2872+
break;
2873+
}
2874+
bestMatch = bestMatch.nextSibling;
2875+
}
2876+
}
28592877
if (
2860-
firstRemainingChild !== null &&
2861-
firstRemainingChild.kind === VIRTUAL_INSTANCE &&
2862-
firstRemainingChild.data.name === componentInfo.name &&
2863-
firstRemainingChild.data.env === componentInfo.env
2878+
bestMatch !== null &&
2879+
bestMatch.kind === VIRTUAL_INSTANCE &&
2880+
bestMatch.data.name === componentInfo.name &&
2881+
bestMatch.data.env === componentInfo.env &&
2882+
bestMatch.data.key === componentInfo.key
28642883
) {
28652884
// If the previous children had a virtual instance in the same slot
28662885
// with the same name, then we claim it and reuse it for this update.
28672886
// Update it with the latest entry.
2868-
firstRemainingChild.data = componentInfo;
2869-
moveChild(firstRemainingChild);
2870-
previousVirtualInstance = firstRemainingChild;
2887+
bestMatch.data = componentInfo;
2888+
moveChild(bestMatch);
2889+
previousVirtualInstance = bestMatch;
28712890
previousVirtualInstanceWasMount = false;
28722891
} else {
28732892
// Otherwise we create a new instance.
@@ -4321,11 +4340,13 @@ export function attach(
43214340
): InspectedElement | null {
43224341
const canViewSource = false;
43234342

4324-
const key = null; // TODO: Track keys on ReactComponentInfo;
4343+
const componentInfo = virtualInstance.data;
4344+
const key =
4345+
typeof componentInfo.key === 'string' ? componentInfo.key : null;
43254346
const props = null; // TODO: Track props on ReactComponentInfo;
43264347

4327-
const env = virtualInstance.data.env;
4328-
let displayName = virtualInstance.data.name || '';
4348+
const env = componentInfo.env;
4349+
let displayName = componentInfo.name || '';
43294350
if (typeof env === 'string') {
43304351
// We model environment as an HoC name for now.
43314352
displayName = env + '(' + displayName + ')';
@@ -4384,7 +4405,7 @@ export function attach(
43844405
// Does the component have legacy context attached to it.
43854406
hasLegacyContext: false,
43864407

4387-
key: key != null ? key : null,
4408+
key: key,
43884409

43894410
displayName: displayName,
43904411
type: ElementTypeVirtual,

0 commit comments

Comments
 (0)