@samitouri / QOS-React / commits / 5b120d6b24

Add a separate button for logging values

Dan Abramov committed Apr 8, 2019 at 18:37 UTC 5b120d6b24e29972ec8bc8b00638051c55f08a43
6 files changed +81 -4
src/backend/agent.js
+10
@@ -75,6 +75,7 @@ export default class Agent extends EventEmitter {
75 bridge.addListener('getProfilingSummary', this.getProfilingSummary);
76 bridge.addListener('highlightElementInDOM', this.highlightElementInDOM);
77 bridge.addListener('inspectElement', this.inspectElement);
78 + bridge.addListener('logElementToConsole', this.logElementToConsole);
79 bridge.addListener('overrideContext', this.overrideContext);
80 bridge.addListener('overrideHookState', this.overrideHookState);
81 bridge.addListener('overrideProps', this.overrideProps);
@@ -268,6 +269,15 @@ export default class Agent extends EventEmitter {
269 }
270 };
271
272 + logElementToConsole = ({ id, rendererID }: InspectSelectParams) => {
273 + const renderer = this._rendererInterfaces[rendererID];
274 + if (renderer == null) {
275 + console.warn(`Invalid renderer id "${rendererID}" for element "${id}"`);
276 + } else {
277 + renderer.logElementToConsole(id);
278 + }
279 + };
280 +
281 reloadAndProfile = () => {
282 localStorage.setItem(LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY, 'true');
283
src/backend/renderer.js
+40
@@ -1530,6 +1530,8 @@ export function attach(
1530 // Can view component source location.
1531 canViewSource,
1532
1533 + displayName: getDataForFiber(fiber).displayName,
1534 +
1535 // Inspectable properties.
1536 // TODO Review sanitization approach for the below inspectable values.
1537 context,
@@ -1560,6 +1562,43 @@ export function attach(
1562 return result;
1563 }
1564
1565 + function logElementToConsole(id) {
1566 + const result = inspectElementRaw(id);
1567 + if (result === null) {
1568 + console.warn(`Could not find Fiber with id "${id}"`);
1569 + return;
1570 + }
1571 +
1572 + const supportsGroup = typeof console.groupCollapsed === 'function';
1573 + const label =
1574 + '[Click to expand] <' + (result.displayName || 'Component') + ' />';
1575 +
1576 + if (supportsGroup) {
1577 + console.groupCollapsed(label);
1578 + }
1579 + if (result.props !== null) {
1580 + console.log('Props:', result.props);
1581 + }
1582 + if (result.state !== null) {
1583 + console.log('State:', result.state);
1584 + }
1585 + if (result.hooks !== null) {
1586 + console.log('Hooks:', result.hooks);
1587 + }
1588 + const nativeNode = findNativeByFiberID(id);
1589 + if (nativeNode !== null) {
1590 + console.log('Node:', nativeNode);
1591 + }
1592 + if (window.chrome || /firefox/i.test(navigator.userAgent)) {
1593 + console.log(
1594 + 'Right-click any value to save it as a global variable for further inspection.'
1595 + );
1596 + }
1597 + if (supportsGroup) {
1598 + console.groupEnd();
1599 + }
1600 + }
1601 +
1602 function setInHook(
1603 id: number,
1604 index: number,
@@ -1870,6 +1909,7 @@ export function attach(
1909 handleCommitFiberRoot,
1910 handleCommitFiberUnmount,
1911 inspectElement,
1912 + logElementToConsole,
1913 prepareViewElementSource,
1914 overrideSuspense,
1915 renderer,
src/backend/types.js
+1
@@ -106,6 +106,7 @@ export type RendererInterface = {
106 handleCommitFiberRoot: (fiber: Object) => void,
107 handleCommitFiberUnmount: (fiber: Object) => void,
108 inspectElement: (id: number) => InspectedElement | null,
109 + logElementToConsole: (id: number) => void,
110 overrideSuspense: (id: number, forceFallback: boolean) => void,
111 prepareViewElementSource: (id: number) => void,
112 renderer: ReactRenderer | null,
src/devtools/views/ButtonIcon.js
+4
@@ -12,6 +12,7 @@ export type IconType =
12 | 'export'
13 | 'filter'
14 | 'import'
15 + | 'log-data'
16 | 'more'
17 | 'next'
18 | 'previous'
@@ -54,6 +55,9 @@ export default function ButtonIcon({ type }: Props) {
55 case 'import':
56 pathData = PATH_IMPORT;
57 break;
58 + case 'log-data':
59 + pathData = PATH_EXPORT; // TODO: real icon
60 + break;
61 case 'more':
62 pathData = PATH_MORE;
63 break;
src/devtools/views/Components/SelectedElement.js
+24 -4
@@ -39,14 +39,14 @@ export default function SelectedElement(_: Props) {
39 const inspectedElement = useInspectedElement(selectedElementID);
40
41 const highlightElement = useCallback(() => {
42 - if (element !== null && selectedElementID !== null) {
43 - const rendererID =
44 - store.getRendererIDForElement(selectedElementID) || null;
42 + const id = selectedElementID;
43 + if (element !== null && id !== null) {
44 + const rendererID = store.getRendererIDForElement(id);
45 if (rendererID !== null) {
46 bridge.send('highlightElementInDOM', {
47 displayName: element.displayName,
48 hideAfterTimeout: true,
49 - id: selectedElementID,
49 + id,
50 rendererID,
51 scrollIntoView: true,
52 });
@@ -54,6 +54,19 @@ export default function SelectedElement(_: Props) {
54 }
55 }, [bridge, element, selectedElementID, store]);
56
57 + const logElement = useCallback(() => {
58 + const id = selectedElementID;
59 + if (id !== null) {
60 + const rendererID = store.getRendererIDForElement(id);
61 + if (rendererID !== null) {
62 + bridge.send('logElementToConsole', {
63 + id,
64 + rendererID,
65 + });
66 + }
67 + }
68 + }, [bridge, selectedElementID, store]);
69 +
70 const viewSource = useCallback(() => {
71 if (viewElementSource != null && selectedElementID !== null) {
72 viewElementSource(selectedElementID);
@@ -89,6 +102,13 @@ export default function SelectedElement(_: Props) {
102 >
103 <ButtonIcon type="view-dom" />
104 </Button>
105 + <Button
106 + className={styles.IconButton}
107 + onClick={logElement}
108 + title="Log this component data to the console"
109 + >
110 + <ButtonIcon type="log-data" />
111 + </Button>
112 <Button
113 className={styles.IconButton}
114 disabled={!canViewSource}
src/devtools/views/Components/types.js
+2
@@ -58,6 +58,8 @@ export type InspectedElement = {|
58
59 // Location of component in source coude.
60 source: Object | null,
61 +
62 + displayName: string | null,
63 |};
64
65 // TODO: Add profiling type