mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[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">
This commit is contained in:
@@ -237,6 +237,8 @@ export function getInternalReactConstants(
|
||||
HostComponent: 5,
|
||||
HostPortal: 4,
|
||||
HostRoot: 3,
|
||||
HostResource: 26, // In reality, 18.2+. But doesn't hurt to include it here
|
||||
HostSingleton: 27, // Same as above
|
||||
HostText: 6,
|
||||
IncompleteClassComponent: 17,
|
||||
IndeterminateComponent: 2,
|
||||
@@ -269,6 +271,8 @@ export function getInternalReactConstants(
|
||||
HostComponent: 5,
|
||||
HostPortal: 4,
|
||||
HostRoot: 3,
|
||||
HostResource: -1, // Doesn't exist yet
|
||||
HostSingleton: -1, // Doesn't exist yet
|
||||
HostText: 6,
|
||||
IncompleteClassComponent: 17,
|
||||
IndeterminateComponent: 2,
|
||||
@@ -300,6 +304,8 @@ export function getInternalReactConstants(
|
||||
HostComponent: 5,
|
||||
HostPortal: 4,
|
||||
HostRoot: 3,
|
||||
HostResource: -1, // Doesn't exist yet
|
||||
HostSingleton: -1, // Doesn't exist yet
|
||||
HostText: 6,
|
||||
IncompleteClassComponent: 17,
|
||||
IndeterminateComponent: 2,
|
||||
@@ -331,6 +337,8 @@ export function getInternalReactConstants(
|
||||
HostComponent: 7,
|
||||
HostPortal: 6,
|
||||
HostRoot: 5,
|
||||
HostResource: -1, // Doesn't exist yet
|
||||
HostSingleton: -1, // Doesn't exist yet
|
||||
HostText: 8,
|
||||
IncompleteClassComponent: -1, // Doesn't exist yet
|
||||
IndeterminateComponent: 4,
|
||||
@@ -362,6 +370,8 @@ export function getInternalReactConstants(
|
||||
HostComponent: 5,
|
||||
HostPortal: 4,
|
||||
HostRoot: 3,
|
||||
HostResource: -1, // Doesn't exist yet
|
||||
HostSingleton: -1, // Doesn't exist yet
|
||||
HostText: 6,
|
||||
IncompleteClassComponent: -1, // Doesn't exist yet
|
||||
IndeterminateComponent: 0,
|
||||
@@ -401,6 +411,8 @@ export function getInternalReactConstants(
|
||||
IndeterminateComponent,
|
||||
ForwardRef,
|
||||
HostRoot,
|
||||
HostResource,
|
||||
HostSingleton,
|
||||
HostComponent,
|
||||
HostPortal,
|
||||
HostText,
|
||||
@@ -466,6 +478,8 @@ export function getInternalReactConstants(
|
||||
}
|
||||
return null;
|
||||
case HostComponent:
|
||||
case HostSingleton:
|
||||
case HostResource:
|
||||
return type;
|
||||
case HostPortal:
|
||||
case HostText:
|
||||
@@ -600,6 +614,8 @@ export function attach(
|
||||
Fragment,
|
||||
FunctionComponent,
|
||||
HostRoot,
|
||||
HostResource,
|
||||
HostSingleton,
|
||||
HostPortal,
|
||||
HostComponent,
|
||||
HostText,
|
||||
@@ -1044,6 +1060,8 @@ export function attach(
|
||||
case HostRoot:
|
||||
return ElementTypeRoot;
|
||||
case HostComponent:
|
||||
case HostResource:
|
||||
case HostSingleton:
|
||||
return ElementTypeHostComponent;
|
||||
case HostPortal:
|
||||
case HostText:
|
||||
|
||||
@@ -40,6 +40,8 @@ export type WorkTagMap = {
|
||||
HostComponent: WorkTag,
|
||||
HostPortal: WorkTag,
|
||||
HostRoot: WorkTag,
|
||||
HostResource: WorkTag,
|
||||
HostSingleton: WorkTag,
|
||||
HostText: WorkTag,
|
||||
IncompleteClassComponent: WorkTag,
|
||||
IndeterminateComponent: WorkTag,
|
||||
|
||||
+43
-39
@@ -9,6 +9,7 @@
|
||||
|
||||
import {copy} from 'clipboard-js';
|
||||
import * as React from 'react';
|
||||
import {ElementTypeHostComponent} from 'react-devtools-shared/src/types';
|
||||
import Button from '../Button';
|
||||
import ButtonIcon from '../ButtonIcon';
|
||||
import KeyValue from './KeyValue';
|
||||
@@ -33,52 +34,55 @@ export default function InspectedElementStateTree({
|
||||
inspectedElement,
|
||||
store,
|
||||
}: Props): React.Node {
|
||||
const {state} = inspectedElement;
|
||||
const {state, type} = inspectedElement;
|
||||
|
||||
// HostSingleton and HostResource may have state that we don't want to expose to users
|
||||
const isHostComponent = type === ElementTypeHostComponent;
|
||||
|
||||
const entries = state != null ? Object.entries(state) : null;
|
||||
const isEmpty = entries === null || entries.length === 0;
|
||||
|
||||
if (isEmpty || isHostComponent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (entries !== null) {
|
||||
entries.sort(alphaSortEntries);
|
||||
}
|
||||
|
||||
const isEmpty = entries === null || entries.length === 0;
|
||||
|
||||
const handleCopy = () => copy(serializeDataForCopy(((state: any): Object)));
|
||||
|
||||
if (isEmpty) {
|
||||
return null;
|
||||
} else {
|
||||
return (
|
||||
<div className={styles.InspectedElementTree}>
|
||||
<div className={styles.HeaderRow}>
|
||||
<div className={styles.Header}>state</div>
|
||||
{!isEmpty && (
|
||||
<Button onClick={handleCopy} title="Copy to clipboard">
|
||||
<ButtonIcon type="copy" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{isEmpty && <div className={styles.Empty}>None</div>}
|
||||
{!isEmpty &&
|
||||
(entries: any).map(([name, value]) => (
|
||||
<KeyValue
|
||||
key={name}
|
||||
alphaSort={true}
|
||||
bridge={bridge}
|
||||
canDeletePaths={true}
|
||||
canEditValues={true}
|
||||
canRenamePaths={true}
|
||||
depth={1}
|
||||
element={element}
|
||||
hidden={false}
|
||||
inspectedElement={inspectedElement}
|
||||
name={name}
|
||||
path={[name]}
|
||||
pathRoot="state"
|
||||
store={store}
|
||||
value={value}
|
||||
/>
|
||||
))}
|
||||
return (
|
||||
<div className={styles.InspectedElementTree}>
|
||||
<div className={styles.HeaderRow}>
|
||||
<div className={styles.Header}>state</div>
|
||||
{!isEmpty && (
|
||||
<Button onClick={handleCopy} title="Copy to clipboard">
|
||||
<ButtonIcon type="copy" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
{isEmpty && <div className={styles.Empty}>None</div>}
|
||||
{!isEmpty &&
|
||||
(entries: any).map(([name, value]) => (
|
||||
<KeyValue
|
||||
key={name}
|
||||
alphaSort={true}
|
||||
bridge={bridge}
|
||||
canDeletePaths={true}
|
||||
canEditValues={true}
|
||||
canRenamePaths={true}
|
||||
depth={1}
|
||||
element={element}
|
||||
hidden={false}
|
||||
inspectedElement={inspectedElement}
|
||||
name={name}
|
||||
path={[name]}
|
||||
pathRoot="state"
|
||||
store={store}
|
||||
value={value}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
+1
-1
@@ -373,7 +373,7 @@ export default function ComponentsSettings(_: {}): React.Node {
|
||||
<option value={ElementTypeFunction}>function</option>
|
||||
<option value={ElementTypeForwardRef}>forward ref</option>
|
||||
<option value={ElementTypeHostComponent}>
|
||||
host (e.g. <div>)
|
||||
dom nodes (e.g. <div>)
|
||||
</option>
|
||||
<option value={ElementTypeMemo}>memo</option>
|
||||
<option value={ElementTypeOtherOrUnknown}>other</option>
|
||||
|
||||
Reference in New Issue
Block a user