diff --git a/packages/react-devtools-shared/src/backend/legacy/renderer.js b/packages/react-devtools-shared/src/backend/legacy/renderer.js index bf8f809c8515b..d68ee86c62cbb 100644 --- a/packages/react-devtools-shared/src/backend/legacy/renderer.js +++ b/packages/react-devtools-shared/src/backend/legacy/renderer.js @@ -802,6 +802,10 @@ export function attach( // Location of component in source coude. source, + + rootType: null, + rendererPackageName: null, + rendererVersion: null, }; } diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index ec3cf61b6548b..d39ec771ca60c 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -2278,6 +2278,16 @@ export function attach( } } + let rootType = null; + let current = fiber; + while (current.return !== null) { + current = current.return; + } + const fiberRoot = current.stateNode; + if (fiberRoot != null && fiberRoot._debugRootType !== null) { + rootType = fiberRoot._debugRootType; + } + return { id, @@ -2318,6 +2328,10 @@ export function attach( // Location of component in source coude. source: _debugSource || null, + + rootType, + rendererPackageName: renderer.rendererPackageName, + rendererVersion: renderer.version, }; } diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index 4b5091e3bf532..024a4876b5d61 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -87,6 +87,7 @@ export type ReactProviderType = { export type ReactRenderer = { findFiberByHostInstance: (hostInstance: NativeType) => ?Fiber, version: string, + rendererPackageName: string, bundleType: BundleType, // 16.9+ overrideHookState?: ?( @@ -207,10 +208,17 @@ export type InspectedElement = {| // List of owners owners: Array | null, - // Location of component in source coude. + // Location of component in source code. source: Source | null, type: ElementType, + + // Meta information about the root this element belongs to. + rootType: string | null, + + // Meta information about the renderer that created this element. + rendererPackageName: string | null, + rendererVersion: string | null, |}; export const InspectElementFullDataType = 'full-data'; diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Badge.js b/packages/react-devtools-shared/src/devtools/views/Components/Badge.js index a2c37b801e170..aad4848426aa5 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/Badge.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/Badge.js @@ -26,12 +26,12 @@ export default function Badge({ type, children, }: Props) { - let totalBadgeCount = 0; - - if (hocDisplayNames !== null) { - totalBadgeCount += hocDisplayNames.length; + if (hocDisplayNames === null) { + return null; } + const totalBadgeCount = hocDisplayNames.length; + return (
{children}
diff --git a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementContext.js b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementContext.js index c88cc35438393..4354bc5399b44 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementContext.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementContext.js @@ -208,6 +208,9 @@ function InspectedElementContextController({children}: Props) { context, hooks, props, + rendererPackageName, + rendererVersion, + rootType, state, key, } = ((data.value: any): InspectedElementBackend); @@ -220,6 +223,9 @@ function InspectedElementContextController({children}: Props) { hasLegacyContext, id, key, + rendererPackageName, + rendererVersion, + rootType, source, type, owners: diff --git a/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.css b/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.css index 377a428e96cfc..32a6c344cca75 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.css +++ b/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.css @@ -153,3 +153,10 @@ .ContextMenuIcon { margin-right: 0.5rem; } + +.OwnersMetaField { + padding-left: 1.25rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} \ No newline at end of file diff --git a/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.js b/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.js index 40f45334e61d5..e3cc5d63751a7 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.js @@ -45,7 +45,7 @@ import type { InspectedElementContextType, StoreAsGlobal, } from './InspectedElementContext'; -import type {Element, InspectedElement} from './types'; +import type {Element, InspectedElement, Owner} from './types'; import type {ElementType} from 'react-devtools-shared/src/types'; export type Props = {||}; @@ -291,11 +291,13 @@ function InspectedElementView({ hooks, owners, props, + rendererPackageName, + rendererVersion, + rootType, source, state, } = inspectedElement; - const {ownerID} = useContext(TreeStateContext); const bridge = useContext(BridgeContext); const store = useContext(StoreContext); @@ -374,6 +376,14 @@ function InspectedElementView({ }; } + const rendererLabel = + rendererPackageName !== null && rendererVersion !== null + ? `${rendererPackageName}@${rendererVersion}` + : null; + const showOwnersList = owners !== null && owners.length > 0; + const showRenderedBy = + showOwnersList || rendererLabel !== null || rootType !== null; + return (
@@ -415,19 +425,26 @@ function InspectedElementView({ - {ownerID === null && owners !== null && owners.length > 0 && ( + {showRenderedBy && (
rendered by
- {owners.map(owner => ( - - ))} + {showOwnersList && + ((owners: any): Array).map(owner => ( + + ))} + {rootType !== null && ( +
{rootType}
+ )} + {rendererLabel !== null && ( +
{rendererLabel}
+ )}
)} diff --git a/packages/react-devtools-shared/src/devtools/views/Components/types.js b/packages/react-devtools-shared/src/devtools/views/Components/types.js index cb50af783e397..dc3a3f6a54990 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/types.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/types.js @@ -88,6 +88,13 @@ export type InspectedElement = {| source: Source | null, type: ElementType, + + // Meta information about the root this element belongs to. + rootType: string | null, + + // Meta information about the renderer that created this element. + rendererPackageName: string | null, + rendererVersion: string | null, |}; // TODO: Add profiling type diff --git a/packages/react-reconciler/src/ReactFiberRoot.new.js b/packages/react-reconciler/src/ReactFiberRoot.new.js index 96f795cbdf279..4585fd05cea8c 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.new.js +++ b/packages/react-reconciler/src/ReactFiberRoot.new.js @@ -24,6 +24,7 @@ import { } from 'shared/ReactFeatureFlags'; import {unstable_getThreadID} from 'scheduler/tracing'; import {initializeUpdateQueue} from './ReactUpdateQueue.new'; +import {LegacyRoot, BlockingRoot, ConcurrentRoot} from './ReactRootTags'; function FiberRootNode(containerInfo, tag, hydrate) { this.tag = tag; @@ -60,6 +61,20 @@ function FiberRootNode(containerInfo, tag, hydrate) { if (enableSuspenseCallback) { this.hydrationCallbacks = null; } + + if (__DEV__) { + switch (tag) { + case BlockingRoot: + this._debugRootType = 'createBlockingRoot()'; + break; + case ConcurrentRoot: + this._debugRootType = 'createRoot()'; + break; + case LegacyRoot: + this._debugRootType = 'createLegacyRoot()'; + break; + } + } } export function createFiberRoot( diff --git a/packages/react-reconciler/src/ReactFiberRoot.old.js b/packages/react-reconciler/src/ReactFiberRoot.old.js index 72d03a596925d..03e33b13fbc54 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.old.js +++ b/packages/react-reconciler/src/ReactFiberRoot.old.js @@ -22,6 +22,7 @@ import {unstable_getThreadID} from 'scheduler/tracing'; import {NoPriority} from './SchedulerWithReactIntegration.old'; import {initializeUpdateQueue} from './ReactUpdateQueue.old'; import {clearPendingUpdates as clearPendingMutableSourceUpdates} from './ReactMutableSource.old'; +import {LegacyRoot, BlockingRoot, ConcurrentRoot} from './ReactRootTags'; function FiberRootNode(containerInfo, tag, hydrate) { this.tag = tag; @@ -54,6 +55,20 @@ function FiberRootNode(containerInfo, tag, hydrate) { if (enableSuspenseCallback) { this.hydrationCallbacks = null; } + + if (__DEV__) { + switch (tag) { + case BlockingRoot: + this._debugRootType = 'createBlockingRoot()'; + break; + case ConcurrentRoot: + this._debugRootType = 'createRoot()'; + break; + case LegacyRoot: + this._debugRootType = 'createLegacyRoot()'; + break; + } + } } export function createFiberRoot(