DevTools: Add root and renderer version to inspected props panel (#18963)
* DevTools: Add root and renderer version to inspected props panel * Removed redundant .length check
Brian Vaughn committed
May 21, 2020 at 14:40 UTC
aefb97e6bb2874e48a08cb87366bc4ca3aa99a7d
10 files changed
+111
-18
packages/react-devtools-shared/src/backend/legacy/renderer.js
+4
@@ -802,6 +802,10 @@ export function attach(
802
803
// Location of component in source coude.
804
source,
805
+
806
+ rootType: null,
807
+ rendererPackageName: null,
808
+ rendererVersion: null,
809
};
810
}
811
packages/react-devtools-shared/src/backend/renderer.js
+14
@@ -2278,6 +2278,16 @@ export function attach(
2278
}
2279
}
2280
2281
+ let rootType = null;
2282
+ let current = fiber;
2283
+ while (current.return !== null) {
2284
+ current = current.return;
2285
+ }
2286
+ const fiberRoot = current.stateNode;
2287
+ if (fiberRoot != null && fiberRoot._debugRootType !== null) {
2288
+ rootType = fiberRoot._debugRootType;
2289
+ }
2290
+
2291
return {
2292
id,
2293
@@ -2318,6 +2328,10 @@ export function attach(
2328
2329
// Location of component in source coude.
2330
source: _debugSource || null,
2331
+
2332
+ rootType,
2333
+ rendererPackageName: renderer.rendererPackageName,
2334
+ rendererVersion: renderer.version,
2335
};
2336
}
2337
packages/react-devtools-shared/src/backend/types.js
+9
-1
@@ -87,6 +87,7 @@ export type ReactProviderType<T> = {
87
export type ReactRenderer = {
88
findFiberByHostInstance: (hostInstance: NativeType) => ?Fiber,
89
version: string,
90
+ rendererPackageName: string,
91
bundleType: BundleType,
92
// 16.9+
93
overrideHookState?: ?(
@@ -207,10 +208,17 @@ export type InspectedElement = {|
208
// List of owners
209
owners: Array<Owner> | null,
210
210
- // Location of component in source coude.
211
+ // Location of component in source code.
212
source: Source | null,
213
214
type: ElementType,
215
+
216
+ // Meta information about the root this element belongs to.
217
+ rootType: string | null,
218
+
219
+ // Meta information about the renderer that created this element.
220
+ rendererPackageName: string | null,
221
+ rendererVersion: string | null,
222
|};
223
224
export const InspectElementFullDataType = 'full-data';
packages/react-devtools-shared/src/devtools/views/Components/Badge.js
+4
-4
@@ -26,12 +26,12 @@ export default function Badge({
26
type,
27
children,
28
}: Props) {
29
- let totalBadgeCount = 0;
30
-
31
- if (hocDisplayNames !== null) {
32
- totalBadgeCount += hocDisplayNames.length;
29
+ if (hocDisplayNames === null) {
30
+ return null;
31
}
32
33
+ const totalBadgeCount = hocDisplayNames.length;
34
+
35
return (
36
<Fragment>
37
<div className={`${styles.Badge} ${className || ''}`}>{children}</div>
packages/react-devtools-shared/src/devtools/views/Components/InspectedElementContext.js
+6
@@ -208,6 +208,9 @@ function InspectedElementContextController({children}: Props) {
208
context,
209
hooks,
210
props,
211
+ rendererPackageName,
212
+ rendererVersion,
213
+ rootType,
214
state,
215
key,
216
} = ((data.value: any): InspectedElementBackend);
@@ -220,6 +223,9 @@ function InspectedElementContextController({children}: Props) {
223
hasLegacyContext,
224
id,
225
key,
226
+ rendererPackageName,
227
+ rendererVersion,
228
+ rootType,
229
source,
230
type,
231
owners:
packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.css
+7
@@ -153,3 +153,10 @@
153
.ContextMenuIcon {
154
margin-right: 0.5rem;
155
}
156
+
157
+.OwnersMetaField {
158
+ padding-left: 1.25rem;
159
+ white-space: nowrap;
160
+ overflow: hidden;
161
+ text-overflow: ellipsis;
162
+}
\ No newline at end of file
packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.js
+30
-13
@@ -45,7 +45,7 @@ import type {
45
InspectedElementContextType,
46
StoreAsGlobal,
47
} from './InspectedElementContext';
48
-import type {Element, InspectedElement} from './types';
48
+import type {Element, InspectedElement, Owner} from './types';
49
import type {ElementType} from 'react-devtools-shared/src/types';
50
51
export type Props = {||};
@@ -291,11 +291,13 @@ function InspectedElementView({
291
hooks,
292
owners,
293
props,
294
+ rendererPackageName,
295
+ rendererVersion,
296
+ rootType,
297
source,
298
state,
299
} = inspectedElement;
300
298
- const {ownerID} = useContext(TreeStateContext);
301
const bridge = useContext(BridgeContext);
302
const store = useContext(StoreContext);
303
@@ -374,6 +376,14 @@ function InspectedElementView({
376
};
377
}
378
379
+ const rendererLabel =
380
+ rendererPackageName !== null && rendererVersion !== null
381
+ ? `${rendererPackageName}@${rendererVersion}`
382
+ : null;
383
+ const showOwnersList = owners !== null && owners.length > 0;
384
+ const showRenderedBy =
385
+ showOwnersList || rendererLabel !== null || rootType !== null;
386
+
387
return (
388
<Fragment>
389
<div className={styles.InspectedElement}>
@@ -415,19 +425,26 @@ function InspectedElementView({
425
426
<NativeStyleEditor />
427
418
- {ownerID === null && owners !== null && owners.length > 0 && (
428
+ {showRenderedBy && (
429
<div className={styles.Owners}>
430
<div className={styles.OwnersHeader}>rendered by</div>
421
- {owners.map(owner => (
422
- <OwnerView
423
- key={owner.id}
424
- displayName={owner.displayName || 'Anonymous'}
425
- hocDisplayNames={owner.hocDisplayNames}
426
- id={owner.id}
427
- isInStore={store.containsElement(owner.id)}
428
- type={owner.type}
429
- />
430
- ))}
431
+ {showOwnersList &&
432
+ ((owners: any): Array<Owner>).map(owner => (
433
+ <OwnerView
434
+ key={owner.id}
435
+ displayName={owner.displayName || 'Anonymous'}
436
+ hocDisplayNames={owner.hocDisplayNames}
437
+ id={owner.id}
438
+ isInStore={store.containsElement(owner.id)}
439
+ type={owner.type}
440
+ />
441
+ ))}
442
+ {rootType !== null && (
443
+ <div className={styles.OwnersMetaField}>{rootType}</div>
444
+ )}
445
+ {rendererLabel !== null && (
446
+ <div className={styles.OwnersMetaField}>{rendererLabel}</div>
447
+ )}
448
</div>
449
)}
450
packages/react-devtools-shared/src/devtools/views/Components/types.js
+7
@@ -88,6 +88,13 @@ export type InspectedElement = {|
88
source: Source | null,
89
90
type: ElementType,
91
+
92
+ // Meta information about the root this element belongs to.
93
+ rootType: string | null,
94
+
95
+ // Meta information about the renderer that created this element.
96
+ rendererPackageName: string | null,
97
+ rendererVersion: string | null,
98
|};
99
100
// TODO: Add profiling type
packages/react-reconciler/src/ReactFiberRoot.new.js
+15
@@ -24,6 +24,7 @@ import {
24
} from 'shared/ReactFeatureFlags';
25
import {unstable_getThreadID} from 'scheduler/tracing';
26
import {initializeUpdateQueue} from './ReactUpdateQueue.new';
27
+import {LegacyRoot, BlockingRoot, ConcurrentRoot} from './ReactRootTags';
28
29
function FiberRootNode(containerInfo, tag, hydrate) {
30
this.tag = tag;
@@ -60,6 +61,20 @@ function FiberRootNode(containerInfo, tag, hydrate) {
61
if (enableSuspenseCallback) {
62
this.hydrationCallbacks = null;
63
}
64
+
65
+ if (__DEV__) {
66
+ switch (tag) {
67
+ case BlockingRoot:
68
+ this._debugRootType = 'createBlockingRoot()';
69
+ break;
70
+ case ConcurrentRoot:
71
+ this._debugRootType = 'createRoot()';
72
+ break;
73
+ case LegacyRoot:
74
+ this._debugRootType = 'createLegacyRoot()';
75
+ break;
76
+ }
77
+ }
78
}
79
80
export function createFiberRoot(
packages/react-reconciler/src/ReactFiberRoot.old.js
+15
@@ -22,6 +22,7 @@ import {unstable_getThreadID} from 'scheduler/tracing';
22
import {NoPriority} from './SchedulerWithReactIntegration.old';
23
import {initializeUpdateQueue} from './ReactUpdateQueue.old';
24
import {clearPendingUpdates as clearPendingMutableSourceUpdates} from './ReactMutableSource.old';
25
+import {LegacyRoot, BlockingRoot, ConcurrentRoot} from './ReactRootTags';
26
27
function FiberRootNode(containerInfo, tag, hydrate) {
28
this.tag = tag;
@@ -54,6 +55,20 @@ function FiberRootNode(containerInfo, tag, hydrate) {
55
if (enableSuspenseCallback) {
56
this.hydrationCallbacks = null;
57
}
58
+
59
+ if (__DEV__) {
60
+ switch (tag) {
61
+ case BlockingRoot:
62
+ this._debugRootType = 'createBlockingRoot()';
63
+ break;
64
+ case ConcurrentRoot:
65
+ this._debugRootType = 'createRoot()';
66
+ break;
67
+ case LegacyRoot:
68
+ this._debugRootType = 'createLegacyRoot()';
69
+ break;
70
+ }
71
+ }
72
}
73
74
export function createFiberRoot(