mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge branch 'inspect-log' of https://github.com/gaearon/react-devtools-experimental into gaearon-inspect-log
This commit is contained in:
@@ -75,6 +75,7 @@ export default class Agent extends EventEmitter {
|
||||
bridge.addListener('getProfilingSummary', this.getProfilingSummary);
|
||||
bridge.addListener('highlightElementInDOM', this.highlightElementInDOM);
|
||||
bridge.addListener('inspectElement', this.inspectElement);
|
||||
bridge.addListener('logElementToConsole', this.logElementToConsole);
|
||||
bridge.addListener('overrideContext', this.overrideContext);
|
||||
bridge.addListener('overrideHookState', this.overrideHookState);
|
||||
bridge.addListener('overrideProps', this.overrideProps);
|
||||
@@ -268,6 +269,15 @@ export default class Agent extends EventEmitter {
|
||||
}
|
||||
};
|
||||
|
||||
logElementToConsole = ({ id, rendererID }: InspectSelectParams) => {
|
||||
const renderer = this._rendererInterfaces[rendererID];
|
||||
if (renderer == null) {
|
||||
console.warn(`Invalid renderer id "${rendererID}" for element "${id}"`);
|
||||
} else {
|
||||
renderer.logElementToConsole(id);
|
||||
}
|
||||
};
|
||||
|
||||
reloadAndProfile = () => {
|
||||
localStorage.setItem(LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY, 'true');
|
||||
|
||||
|
||||
+58
-7
@@ -1410,7 +1410,7 @@ export function attach(
|
||||
}
|
||||
}
|
||||
|
||||
function inspectElement(id: number): InspectedElement | null {
|
||||
function inspectElementRaw(id: number): InspectedElement | null {
|
||||
let fiber = idToFiberMap.get(id);
|
||||
|
||||
if (fiber == null) {
|
||||
@@ -1491,7 +1491,7 @@ export function attach(
|
||||
if (context !== null) {
|
||||
// To simplify hydration and display logic for context, wrap in a value object.
|
||||
// Otherwise simple values (e.g. strings, booleans) become harder to handle.
|
||||
context = cleanForBridge({ value: context });
|
||||
context = { value: context };
|
||||
}
|
||||
|
||||
let owners = null;
|
||||
@@ -1530,16 +1530,16 @@ export function attach(
|
||||
// Can view component source location.
|
||||
canViewSource,
|
||||
|
||||
displayName: getDataForFiber(fiber).displayName,
|
||||
|
||||
// Inspectable properties.
|
||||
// TODO Review sanitization approach for the below inspectable values.
|
||||
context,
|
||||
hooks: usesHooks
|
||||
? cleanForBridge(
|
||||
inspectHooksOfFiber(fiber, (renderer.currentDispatcherRef: any))
|
||||
)
|
||||
? inspectHooksOfFiber(fiber, (renderer.currentDispatcherRef: any))
|
||||
: null,
|
||||
props: cleanForBridge(memoizedProps),
|
||||
state: usesHooks ? null : cleanForBridge(memoizedState),
|
||||
props: memoizedProps,
|
||||
state: usesHooks ? null : memoizedState,
|
||||
|
||||
// List of owners
|
||||
owners,
|
||||
@@ -1549,6 +1549,56 @@ export function attach(
|
||||
};
|
||||
}
|
||||
|
||||
function inspectElement(id: number): InspectedElement | null {
|
||||
let result = inspectElementRaw(id);
|
||||
if (result === null) {
|
||||
return null;
|
||||
}
|
||||
// TODO Review sanitization approach for the below inspectable values.
|
||||
result.context = cleanForBridge(result.context);
|
||||
result.hooks = cleanForBridge(result.hooks);
|
||||
result.props = cleanForBridge(result.props);
|
||||
result.state = cleanForBridge(result.state);
|
||||
return result;
|
||||
}
|
||||
|
||||
function logElementToConsole(id) {
|
||||
const result = inspectElementRaw(id);
|
||||
if (result === null) {
|
||||
console.warn(`Could not find Fiber with id "${id}"`);
|
||||
return;
|
||||
}
|
||||
|
||||
const supportsGroup = typeof console.groupCollapsed === 'function';
|
||||
const label =
|
||||
'[Click to expand] <' + (result.displayName || 'Component') + ' />';
|
||||
|
||||
if (supportsGroup) {
|
||||
console.groupCollapsed(label);
|
||||
}
|
||||
if (result.props !== null) {
|
||||
console.log('Props:', result.props);
|
||||
}
|
||||
if (result.state !== null) {
|
||||
console.log('State:', result.state);
|
||||
}
|
||||
if (result.hooks !== null) {
|
||||
console.log('Hooks:', result.hooks);
|
||||
}
|
||||
const nativeNode = findNativeByFiberID(id);
|
||||
if (nativeNode !== null) {
|
||||
console.log('Node:', nativeNode);
|
||||
}
|
||||
if (window.chrome || /firefox/i.test(navigator.userAgent)) {
|
||||
console.log(
|
||||
'Right-click any value to save it as a global variable for further inspection.'
|
||||
);
|
||||
}
|
||||
if (supportsGroup) {
|
||||
console.groupEnd();
|
||||
}
|
||||
}
|
||||
|
||||
function setInHook(
|
||||
id: number,
|
||||
index: number,
|
||||
@@ -1859,6 +1909,7 @@ export function attach(
|
||||
handleCommitFiberRoot,
|
||||
handleCommitFiberUnmount,
|
||||
inspectElement,
|
||||
logElementToConsole,
|
||||
prepareViewElementSource,
|
||||
overrideSuspense,
|
||||
renderer,
|
||||
|
||||
@@ -106,6 +106,7 @@ export type RendererInterface = {
|
||||
handleCommitFiberRoot: (fiber: Object) => void,
|
||||
handleCommitFiberUnmount: (fiber: Object) => void,
|
||||
inspectElement: (id: number) => InspectedElement | null,
|
||||
logElementToConsole: (id: number) => void,
|
||||
overrideSuspense: (id: number, forceFallback: boolean) => void,
|
||||
prepareViewElementSource: (id: number) => void,
|
||||
renderer: ReactRenderer | null,
|
||||
|
||||
@@ -12,6 +12,7 @@ export type IconType =
|
||||
| 'export'
|
||||
| 'filter'
|
||||
| 'import'
|
||||
| 'log-data'
|
||||
| 'more'
|
||||
| 'next'
|
||||
| 'previous'
|
||||
@@ -54,6 +55,9 @@ export default function ButtonIcon({ type }: Props) {
|
||||
case 'import':
|
||||
pathData = PATH_IMPORT;
|
||||
break;
|
||||
case 'log-data':
|
||||
pathData = PATH_EXPORT; // TODO: real icon
|
||||
break;
|
||||
case 'more':
|
||||
pathData = PATH_MORE;
|
||||
break;
|
||||
|
||||
@@ -39,14 +39,14 @@ export default function SelectedElement(_: Props) {
|
||||
const inspectedElement = useInspectedElement(selectedElementID);
|
||||
|
||||
const highlightElement = useCallback(() => {
|
||||
if (element !== null && selectedElementID !== null) {
|
||||
const rendererID =
|
||||
store.getRendererIDForElement(selectedElementID) || null;
|
||||
const id = selectedElementID;
|
||||
if (element !== null && id !== null) {
|
||||
const rendererID = store.getRendererIDForElement(id);
|
||||
if (rendererID !== null) {
|
||||
bridge.send('highlightElementInDOM', {
|
||||
displayName: element.displayName,
|
||||
hideAfterTimeout: true,
|
||||
id: selectedElementID,
|
||||
id,
|
||||
rendererID,
|
||||
scrollIntoView: true,
|
||||
});
|
||||
@@ -54,6 +54,19 @@ export default function SelectedElement(_: Props) {
|
||||
}
|
||||
}, [bridge, element, selectedElementID, store]);
|
||||
|
||||
const logElement = useCallback(() => {
|
||||
const id = selectedElementID;
|
||||
if (id !== null) {
|
||||
const rendererID = store.getRendererIDForElement(id);
|
||||
if (rendererID !== null) {
|
||||
bridge.send('logElementToConsole', {
|
||||
id,
|
||||
rendererID,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [bridge, selectedElementID, store]);
|
||||
|
||||
const viewSource = useCallback(() => {
|
||||
if (viewElementSource != null && selectedElementID !== null) {
|
||||
viewElementSource(selectedElementID);
|
||||
@@ -89,6 +102,13 @@ export default function SelectedElement(_: Props) {
|
||||
>
|
||||
<ButtonIcon type="view-dom" />
|
||||
</Button>
|
||||
<Button
|
||||
className={styles.IconButton}
|
||||
onClick={logElement}
|
||||
title="Log this component data to the console"
|
||||
>
|
||||
<ButtonIcon type="log-data" />
|
||||
</Button>
|
||||
<Button
|
||||
className={styles.IconButton}
|
||||
disabled={!canViewSource}
|
||||
|
||||
@@ -58,6 +58,8 @@ export type InspectedElement = {|
|
||||
|
||||
// Location of component in source coude.
|
||||
source: Object | null,
|
||||
|
||||
displayName: string | null,
|
||||
|};
|
||||
|
||||
// TODO: Add profiling type
|
||||
|
||||
Reference in New Issue
Block a user