Skip to content

Commit 18dff79

Browse files
authored
[DevTools] add support for HostSingleton & HostResource (#25616)
## Summary This is to support two new reconciler work tags `HostSingleton` and `HostResource` introduced in PRs #25243 #25426. The behavior is described below. I also renamed an option in components settings from an internal concept "host" to more understood "dom nodes" ## How did you test this change? Tested on the latest Vercel playground app https://github.com/vercel/app-playground/ Before the change, devtools cannot show correct display name for these new elements. Also, some unnecessary internal details are exposed to users. <img width="1395" alt="image" src="https://user-images.githubusercontent.com/1001890/199578181-c4e4ea74-baa1-4507-83d0-91a62ad7de5f.png"> After the change, the display names are correctly shown and the "state" would always be hidden in the detail view. <img width="1417" alt="image" src="https://user-images.githubusercontent.com/1001890/199578442-adc1951d-7d5b-4b84-ad64-85bcf7a8ebcc.png"> These elements will also be hidden just like other native dom elements (e.g. `<div>`) <img width="836" alt="image" src="https://user-images.githubusercontent.com/1001890/199578598-2dfacf64-ddc9-42b5-a246-dd0b09f629af.png">
1 parent 4bd245e commit 18dff79

File tree

4 files changed

+64
-40
lines changed

4 files changed

+64
-40
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ export function getInternalReactConstants(
237237
HostComponent: 5,
238238
HostPortal: 4,
239239
HostRoot: 3,
240+
HostResource: 26, // In reality, 18.2+. But doesn't hurt to include it here
241+
HostSingleton: 27, // Same as above
240242
HostText: 6,
241243
IncompleteClassComponent: 17,
242244
IndeterminateComponent: 2,
@@ -269,6 +271,8 @@ export function getInternalReactConstants(
269271
HostComponent: 5,
270272
HostPortal: 4,
271273
HostRoot: 3,
274+
HostResource: -1, // Doesn't exist yet
275+
HostSingleton: -1, // Doesn't exist yet
272276
HostText: 6,
273277
IncompleteClassComponent: 17,
274278
IndeterminateComponent: 2,
@@ -300,6 +304,8 @@ export function getInternalReactConstants(
300304
HostComponent: 5,
301305
HostPortal: 4,
302306
HostRoot: 3,
307+
HostResource: -1, // Doesn't exist yet
308+
HostSingleton: -1, // Doesn't exist yet
303309
HostText: 6,
304310
IncompleteClassComponent: 17,
305311
IndeterminateComponent: 2,
@@ -331,6 +337,8 @@ export function getInternalReactConstants(
331337
HostComponent: 7,
332338
HostPortal: 6,
333339
HostRoot: 5,
340+
HostResource: -1, // Doesn't exist yet
341+
HostSingleton: -1, // Doesn't exist yet
334342
HostText: 8,
335343
IncompleteClassComponent: -1, // Doesn't exist yet
336344
IndeterminateComponent: 4,
@@ -362,6 +370,8 @@ export function getInternalReactConstants(
362370
HostComponent: 5,
363371
HostPortal: 4,
364372
HostRoot: 3,
373+
HostResource: -1, // Doesn't exist yet
374+
HostSingleton: -1, // Doesn't exist yet
365375
HostText: 6,
366376
IncompleteClassComponent: -1, // Doesn't exist yet
367377
IndeterminateComponent: 0,
@@ -401,6 +411,8 @@ export function getInternalReactConstants(
401411
IndeterminateComponent,
402412
ForwardRef,
403413
HostRoot,
414+
HostResource,
415+
HostSingleton,
404416
HostComponent,
405417
HostPortal,
406418
HostText,
@@ -466,6 +478,8 @@ export function getInternalReactConstants(
466478
}
467479
return null;
468480
case HostComponent:
481+
case HostSingleton:
482+
case HostResource:
469483
return type;
470484
case HostPortal:
471485
case HostText:
@@ -600,6 +614,8 @@ export function attach(
600614
Fragment,
601615
FunctionComponent,
602616
HostRoot,
617+
HostResource,
618+
HostSingleton,
603619
HostPortal,
604620
HostComponent,
605621
HostText,
@@ -1044,6 +1060,8 @@ export function attach(
10441060
case HostRoot:
10451061
return ElementTypeRoot;
10461062
case HostComponent:
1063+
case HostResource:
1064+
case HostSingleton:
10471065
return ElementTypeHostComponent;
10481066
case HostPortal:
10491067
case HostText:

packages/react-devtools-shared/src/backend/types.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ export type WorkTagMap = {
4040
HostComponent: WorkTag,
4141
HostPortal: WorkTag,
4242
HostRoot: WorkTag,
43+
HostResource: WorkTag,
44+
HostSingleton: WorkTag,
4345
HostText: WorkTag,
4446
IncompleteClassComponent: WorkTag,
4547
IndeterminateComponent: WorkTag,

packages/react-devtools-shared/src/devtools/views/Components/InspectedElementStateTree.js

Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import {copy} from 'clipboard-js';
1111
import * as React from 'react';
12+
import {ElementTypeHostComponent} from 'react-devtools-shared/src/types';
1213
import Button from '../Button';
1314
import ButtonIcon from '../ButtonIcon';
1415
import KeyValue from './KeyValue';
@@ -33,52 +34,55 @@ export default function InspectedElementStateTree({
3334
inspectedElement,
3435
store,
3536
}: Props): React.Node {
36-
const {state} = inspectedElement;
37+
const {state, type} = inspectedElement;
38+
39+
// HostSingleton and HostResource may have state that we don't want to expose to users
40+
const isHostComponent = type === ElementTypeHostComponent;
3741

3842
const entries = state != null ? Object.entries(state) : null;
43+
const isEmpty = entries === null || entries.length === 0;
44+
45+
if (isEmpty || isHostComponent) {
46+
return null;
47+
}
48+
3949
if (entries !== null) {
4050
entries.sort(alphaSortEntries);
4151
}
4252

43-
const isEmpty = entries === null || entries.length === 0;
44-
4553
const handleCopy = () => copy(serializeDataForCopy(((state: any): Object)));
4654

47-
if (isEmpty) {
48-
return null;
49-
} else {
50-
return (
51-
<div className={styles.InspectedElementTree}>
52-
<div className={styles.HeaderRow}>
53-
<div className={styles.Header}>state</div>
54-
{!isEmpty && (
55-
<Button onClick={handleCopy} title="Copy to clipboard">
56-
<ButtonIcon type="copy" />
57-
</Button>
58-
)}
59-
</div>
60-
{isEmpty && <div className={styles.Empty}>None</div>}
61-
{!isEmpty &&
62-
(entries: any).map(([name, value]) => (
63-
<KeyValue
64-
key={name}
65-
alphaSort={true}
66-
bridge={bridge}
67-
canDeletePaths={true}
68-
canEditValues={true}
69-
canRenamePaths={true}
70-
depth={1}
71-
element={element}
72-
hidden={false}
73-
inspectedElement={inspectedElement}
74-
name={name}
75-
path={[name]}
76-
pathRoot="state"
77-
store={store}
78-
value={value}
79-
/>
80-
))}
55+
return (
56+
<div className={styles.InspectedElementTree}>
57+
<div className={styles.HeaderRow}>
58+
<div className={styles.Header}>state</div>
59+
{!isEmpty && (
60+
<Button onClick={handleCopy} title="Copy to clipboard">
61+
<ButtonIcon type="copy" />
62+
</Button>
63+
)}
8164
</div>
82-
);
83-
}
65+
{isEmpty && <div className={styles.Empty}>None</div>}
66+
{!isEmpty &&
67+
(entries: any).map(([name, value]) => (
68+
<KeyValue
69+
key={name}
70+
alphaSort={true}
71+
bridge={bridge}
72+
canDeletePaths={true}
73+
canEditValues={true}
74+
canRenamePaths={true}
75+
depth={1}
76+
element={element}
77+
hidden={false}
78+
inspectedElement={inspectedElement}
79+
name={name}
80+
path={[name]}
81+
pathRoot="state"
82+
store={store}
83+
value={value}
84+
/>
85+
))}
86+
</div>
87+
);
8488
}

packages/react-devtools-shared/src/devtools/views/Settings/ComponentsSettings.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ export default function ComponentsSettings(_: {}): React.Node {
373373
<option value={ElementTypeFunction}>function</option>
374374
<option value={ElementTypeForwardRef}>forward ref</option>
375375
<option value={ElementTypeHostComponent}>
376-
host (e.g. &lt;div&gt;)
376+
dom nodes (e.g. &lt;div&gt;)
377377
</option>
378378
<option value={ElementTypeMemo}>memo</option>
379379
<option value={ElementTypeOtherOrUnknown}>other</option>

0 commit comments

Comments
 (0)