mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
refactor[Inspector]: migrate to functional component (#41411)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/41411 Changelog: [Internal] I am planning some changes in this component. No functional changes in this diff, except for the `panelContainerStyle` change for iOS to fix top gap. Reviewed By: robhogan Differential Revision: D50644902 fbshipit-source-id: 3111da100261552c89d0cd4eae724500c446cdfd
This commit is contained in:
committed by
Facebook GitHub Bot
parent
3dd6a83c0e
commit
066cb2bfd5
+27
-23
@@ -10,7 +10,9 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {InspectorData} from '../Renderer/shims/ReactNativeTypes';
|
||||
import type {ViewStyleProp} from '../StyleSheet/StyleSheet';
|
||||
import type {InspectedElementSource} from './Inspector';
|
||||
|
||||
const TouchableHighlight = require('../Components/Touchable/TouchableHighlight');
|
||||
const TouchableWithoutFeedback = require('../Components/Touchable/TouchableWithoutFeedback');
|
||||
@@ -25,13 +27,9 @@ const StyleInspector = require('./StyleInspector');
|
||||
const React = require('react');
|
||||
|
||||
type Props = $ReadOnly<{|
|
||||
hierarchy: Array<{|name: string|}>,
|
||||
hierarchy: ?InspectorData['hierarchy'],
|
||||
style?: ?ViewStyleProp,
|
||||
source?: ?{
|
||||
fileName?: string,
|
||||
lineNumber?: number,
|
||||
...
|
||||
},
|
||||
source?: ?InspectedElementSource,
|
||||
frame?: ?Object,
|
||||
selection?: ?number,
|
||||
setSelection?: number => mixed,
|
||||
@@ -63,23 +61,29 @@ class ElementProperties extends React.Component<Props> {
|
||||
<TouchableWithoutFeedback>
|
||||
<View style={styles.info}>
|
||||
<View style={styles.breadcrumb}>
|
||||
{mapWithSeparator(
|
||||
this.props.hierarchy,
|
||||
(hierarchyItem, i): React.MixedElement => (
|
||||
<TouchableHighlight
|
||||
key={'item-' + i}
|
||||
style={[styles.breadItem, i === selection && styles.selected]}
|
||||
// $FlowFixMe[not-a-function] found when converting React.createClass to ES6
|
||||
onPress={() => this.props.setSelection(i)}>
|
||||
<Text style={styles.breadItemText}>{hierarchyItem.name}</Text>
|
||||
</TouchableHighlight>
|
||||
),
|
||||
(i): React.MixedElement => (
|
||||
<Text key={'sep-' + i} style={styles.breadSep}>
|
||||
▸
|
||||
</Text>
|
||||
),
|
||||
)}
|
||||
{this.props.hierarchy != null &&
|
||||
mapWithSeparator(
|
||||
this.props.hierarchy,
|
||||
(hierarchyItem, i): React.MixedElement => (
|
||||
<TouchableHighlight
|
||||
key={'item-' + i}
|
||||
style={[
|
||||
styles.breadItem,
|
||||
i === selection && styles.selected,
|
||||
]}
|
||||
// $FlowFixMe[not-a-function] found when converting React.createClass to ES6
|
||||
onPress={() => this.props.setSelection(i)}>
|
||||
<Text style={styles.breadItemText}>
|
||||
{hierarchyItem.name}
|
||||
</Text>
|
||||
</TouchableHighlight>
|
||||
),
|
||||
(i): React.MixedElement => (
|
||||
<Text key={'sep-' + i} style={styles.breadSep}>
|
||||
▸
|
||||
</Text>
|
||||
),
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
<View style={styles.col}>
|
||||
|
||||
+116
-134
@@ -10,7 +10,11 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {TouchedViewDataAtPoint} from '../Renderer/shims/ReactNativeTypes';
|
||||
import type {
|
||||
InspectorData,
|
||||
TouchedViewDataAtPoint,
|
||||
} from '../Renderer/shims/ReactNativeTypes';
|
||||
import type {ViewStyleProp} from '../StyleSheet/StyleSheet';
|
||||
import type {ReactDevToolsAgent} from '../Types/ReactDevToolsTypes';
|
||||
import type {HostRef} from './getInspectorDataForViewAtPoint';
|
||||
|
||||
@@ -25,71 +29,68 @@ const InspectorOverlay = require('./InspectorOverlay');
|
||||
const InspectorPanel = require('./InspectorPanel');
|
||||
const React = require('react');
|
||||
|
||||
const {useState} = React;
|
||||
|
||||
type PanelPosition = 'top' | 'bottom';
|
||||
type SelectedTab =
|
||||
| 'elements-inspector'
|
||||
| 'network-profiling'
|
||||
| 'performance-profiling';
|
||||
|
||||
export type InspectedElementFrame = TouchedViewDataAtPoint['frame'];
|
||||
export type InspectedElementSource = InspectorData['source'];
|
||||
export type InspectedElement = $ReadOnly<{
|
||||
frame: InspectedElementFrame,
|
||||
source?: InspectedElementSource,
|
||||
style?: ViewStyleProp,
|
||||
}>;
|
||||
export type ElementsHierarchy = InspectorData['hierarchy'];
|
||||
|
||||
type Props = {
|
||||
inspectedView: ?HostRef,
|
||||
onRequestRerenderApp: () => void,
|
||||
reactDevToolsAgent?: ReactDevToolsAgent,
|
||||
};
|
||||
|
||||
class Inspector extends React.Component<
|
||||
Props,
|
||||
{
|
||||
hierarchy: any,
|
||||
panelPos: string,
|
||||
inspecting: boolean,
|
||||
selection: ?number,
|
||||
perfing: boolean,
|
||||
inspected: any,
|
||||
inspectedView: ?HostRef,
|
||||
networking: boolean,
|
||||
...
|
||||
},
|
||||
> {
|
||||
_setTouchedViewData: ?(TouchedViewDataAtPoint) => void;
|
||||
function Inspector({
|
||||
inspectedView,
|
||||
onRequestRerenderApp,
|
||||
reactDevToolsAgent,
|
||||
}: Props): React.Node {
|
||||
const [selectedTab, setSelectedTab] =
|
||||
useState<?SelectedTab>('elements-inspector');
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
const [panelPosition, setPanelPosition] = useState<PanelPosition>('bottom');
|
||||
const [inspectedElement, setInspectedElement] =
|
||||
useState<?InspectedElement>(null);
|
||||
const [selectionIndex, setSelectionIndex] = useState<?number>(null);
|
||||
const [elementsHierarchy, setElementsHierarchy] =
|
||||
useState<?ElementsHierarchy>(null);
|
||||
|
||||
this.state = {
|
||||
hierarchy: null,
|
||||
panelPos: 'bottom',
|
||||
inspecting: true,
|
||||
perfing: false,
|
||||
inspected: null,
|
||||
selection: null,
|
||||
inspectedView: this.props.inspectedView,
|
||||
networking: false,
|
||||
};
|
||||
}
|
||||
const setSelection = (i: number) => {
|
||||
const hierarchyItem = elementsHierarchy?.[i];
|
||||
if (hierarchyItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._setTouchedViewData = null;
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(newProps: Props) {
|
||||
this.setState({inspectedView: newProps.inspectedView});
|
||||
}
|
||||
|
||||
setSelection(i: number) {
|
||||
const hierarchyItem = this.state.hierarchy[i];
|
||||
// we pass in findNodeHandle as the method is injected
|
||||
// We pass in findNodeHandle as the method is injected
|
||||
const {measure, props, source} =
|
||||
hierarchyItem.getInspectorData(findNodeHandle);
|
||||
|
||||
measure((x, y, width, height, left, top) => {
|
||||
this.setState({
|
||||
inspected: {
|
||||
frame: {left, top, width, height},
|
||||
style: props.style,
|
||||
source,
|
||||
},
|
||||
selection: i,
|
||||
// $FlowFixMe[incompatible-call] `props` from InspectorData are defined as <string, string> dictionary, which is incompatible with ViewStyleProp
|
||||
setInspectedElement({
|
||||
frame: {left, top, width, height},
|
||||
source,
|
||||
style: props.style,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onTouchPoint(locationX: number, locationY: number) {
|
||||
this._setTouchedViewData = viewData => {
|
||||
setSelectionIndex(i);
|
||||
});
|
||||
};
|
||||
|
||||
const onTouchPoint = (locationX: number, locationY: number) => {
|
||||
const setTouchedViewData = (viewData: TouchedViewDataAtPoint) => {
|
||||
const {
|
||||
hierarchy,
|
||||
props,
|
||||
@@ -104,109 +105,90 @@ class Inspector extends React.Component<
|
||||
// Sync the touched view with React DevTools.
|
||||
// Note: This is Paper only. To support Fabric,
|
||||
// DevTools needs to be updated to not rely on view tags.
|
||||
const agent = this.props.reactDevToolsAgent;
|
||||
if (agent) {
|
||||
agent.selectNode(findNodeHandle(touchedViewTag));
|
||||
if (reactDevToolsAgent) {
|
||||
reactDevToolsAgent.selectNode(findNodeHandle(touchedViewTag));
|
||||
if (closestInstance != null) {
|
||||
agent.selectNode(closestInstance);
|
||||
reactDevToolsAgent.selectNode(closestInstance);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
panelPos:
|
||||
pointerY > Dimensions.get('window').height / 2 ? 'top' : 'bottom',
|
||||
selection: selectedIndex,
|
||||
hierarchy,
|
||||
inspected: {
|
||||
style: props.style,
|
||||
frame,
|
||||
source,
|
||||
},
|
||||
setPanelPosition(
|
||||
pointerY > Dimensions.get('window').height / 2 ? 'top' : 'bottom',
|
||||
);
|
||||
setSelectionIndex(selectedIndex);
|
||||
setElementsHierarchy(hierarchy);
|
||||
// $FlowFixMe[incompatible-call] `props` from InspectorData are defined as <string, string> dictionary, which is incompatible with ViewStyleProp
|
||||
setInspectedElement({
|
||||
frame,
|
||||
source,
|
||||
style: props.style,
|
||||
});
|
||||
};
|
||||
|
||||
getInspectorDataForViewAtPoint(
|
||||
this.state.inspectedView,
|
||||
inspectedView,
|
||||
locationX,
|
||||
locationY,
|
||||
viewData => {
|
||||
if (this._setTouchedViewData != null) {
|
||||
this._setTouchedViewData(viewData);
|
||||
this._setTouchedViewData = null;
|
||||
}
|
||||
setTouchedViewData(viewData);
|
||||
return false;
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
setPerfing(val: boolean) {
|
||||
this.setState({
|
||||
perfing: val,
|
||||
inspecting: false,
|
||||
inspected: null,
|
||||
networking: false,
|
||||
});
|
||||
}
|
||||
const setInspecting = (enabled: boolean) => {
|
||||
setSelectedTab(enabled ? 'elements-inspector' : null);
|
||||
setInspectedElement(null);
|
||||
};
|
||||
|
||||
setInspecting(val: boolean) {
|
||||
this.setState({
|
||||
inspecting: val,
|
||||
inspected: null,
|
||||
});
|
||||
}
|
||||
const setPerfing = (enabled: boolean) => {
|
||||
setSelectedTab(enabled ? 'performance-profiling' : null);
|
||||
setInspectedElement(null);
|
||||
};
|
||||
|
||||
setTouchTargeting(val: boolean) {
|
||||
const setNetworking = (enabled: boolean) => {
|
||||
setSelectedTab(enabled ? 'network-profiling' : null);
|
||||
setInspectedElement(null);
|
||||
};
|
||||
|
||||
const setTouchTargeting = (val: boolean) => {
|
||||
PressabilityDebug.setEnabled(val);
|
||||
this.props.onRequestRerenderApp();
|
||||
}
|
||||
onRequestRerenderApp();
|
||||
};
|
||||
|
||||
setNetworking(val: boolean) {
|
||||
this.setState({
|
||||
networking: val,
|
||||
perfing: false,
|
||||
inspecting: false,
|
||||
inspected: null,
|
||||
});
|
||||
}
|
||||
const panelContainerStyle =
|
||||
panelPosition === 'bottom'
|
||||
? {bottom: 0}
|
||||
: Platform.select({ios: {top: 0}, default: {top: 0}});
|
||||
|
||||
render(): React.Node {
|
||||
const panelContainerStyle =
|
||||
this.state.panelPos === 'bottom'
|
||||
? {bottom: 0}
|
||||
: {top: Platform.OS === 'ios' ? 20 : 0};
|
||||
return (
|
||||
<View style={styles.container} pointerEvents="box-none">
|
||||
{this.state.inspecting && (
|
||||
<InspectorOverlay
|
||||
inspected={this.state.inspected}
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
onTouchPoint={this.onTouchPoint.bind(this)}
|
||||
/>
|
||||
)}
|
||||
<View style={[styles.panelContainer, panelContainerStyle]}>
|
||||
<InspectorPanel
|
||||
devtoolsIsOpen={!!this.props.reactDevToolsAgent}
|
||||
inspecting={this.state.inspecting}
|
||||
perfing={this.state.perfing}
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
setPerfing={this.setPerfing.bind(this)}
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
setInspecting={this.setInspecting.bind(this)}
|
||||
inspected={this.state.inspected}
|
||||
hierarchy={this.state.hierarchy}
|
||||
selection={this.state.selection}
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
setSelection={this.setSelection.bind(this)}
|
||||
touchTargeting={PressabilityDebug.isEnabled()}
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
setTouchTargeting={this.setTouchTargeting.bind(this)}
|
||||
networking={this.state.networking}
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
setNetworking={this.setNetworking.bind(this)}
|
||||
/>
|
||||
</View>
|
||||
return (
|
||||
<View style={styles.container} pointerEvents="box-none">
|
||||
{selectedTab === 'elements-inspector' && (
|
||||
<InspectorOverlay
|
||||
inspected={inspectedElement}
|
||||
onTouchPoint={onTouchPoint}
|
||||
/>
|
||||
)}
|
||||
|
||||
<View style={[styles.panelContainer, panelContainerStyle]}>
|
||||
<InspectorPanel
|
||||
devtoolsIsOpen={!!reactDevToolsAgent}
|
||||
inspecting={selectedTab === 'elements-inspector'}
|
||||
perfing={selectedTab === 'performance-profiling'}
|
||||
setPerfing={setPerfing}
|
||||
setInspecting={setInspecting}
|
||||
inspected={inspectedElement}
|
||||
hierarchy={elementsHierarchy}
|
||||
selection={selectionIndex}
|
||||
setSelection={setSelection}
|
||||
touchTargeting={PressabilityDebug.isEnabled()}
|
||||
setTouchTargeting={setTouchTargeting}
|
||||
networking={selectedTab === 'network-profiling'}
|
||||
setNetworking={setNetworking}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {ViewStyleProp} from '../StyleSheet/StyleSheet';
|
||||
import type {PressEvent} from '../Types/CoreEventTypes';
|
||||
import type {InspectedElement} from './Inspector';
|
||||
|
||||
const View = require('../Components/View/View');
|
||||
const StyleSheet = require('../StyleSheet/StyleSheet');
|
||||
@@ -19,13 +19,8 @@ const Dimensions = require('../Utilities/Dimensions').default;
|
||||
const ElementBox = require('./ElementBox');
|
||||
const React = require('react');
|
||||
|
||||
type Inspected = $ReadOnly<{|
|
||||
frame?: Object,
|
||||
style?: ViewStyleProp,
|
||||
|}>;
|
||||
|
||||
type Props = $ReadOnly<{|
|
||||
inspected?: Inspected,
|
||||
inspected?: ?InspectedElement,
|
||||
onTouchPoint: (locationX: number, locationY: number) => void,
|
||||
|}>;
|
||||
|
||||
|
||||
+3
-16
@@ -10,7 +10,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {ViewStyleProp} from '../StyleSheet/StyleSheet';
|
||||
import type {ElementsHierarchy, InspectedElement} from './Inspector';
|
||||
|
||||
import SafeAreaView from '../Components/SafeAreaView/SafeAreaView';
|
||||
|
||||
@@ -34,22 +34,10 @@ type Props = $ReadOnly<{|
|
||||
setTouchTargeting: (val: boolean) => void,
|
||||
networking: boolean,
|
||||
setNetworking: (val: boolean) => void,
|
||||
hierarchy?: ?Array<{|name: string|}>,
|
||||
hierarchy?: ?ElementsHierarchy,
|
||||
selection?: ?number,
|
||||
setSelection: number => mixed,
|
||||
inspected?: ?$ReadOnly<{|
|
||||
style?: ?ViewStyleProp,
|
||||
frame?: ?$ReadOnly<{|
|
||||
top?: ?number,
|
||||
left?: ?number,
|
||||
width?: ?number,
|
||||
height: ?number,
|
||||
|}>,
|
||||
source?: ?{|
|
||||
fileName?: string,
|
||||
lineNumber?: number,
|
||||
|},
|
||||
|}>,
|
||||
inspected?: ?InspectedElement,
|
||||
|}>;
|
||||
|
||||
class InspectorPanel extends React.Component<Props> {
|
||||
@@ -71,7 +59,6 @@ class InspectorPanel extends React.Component<Props> {
|
||||
style={this.props.inspected.style}
|
||||
frame={this.props.inspected.frame}
|
||||
source={this.props.inspected.source}
|
||||
// $FlowFixMe[incompatible-type] : Hierarchy should be non-nullable
|
||||
hierarchy={this.props.hierarchy}
|
||||
selection={this.props.selection}
|
||||
setSelection={this.props.setSelection}
|
||||
|
||||
@@ -15,6 +15,7 @@ import type {
|
||||
ReactDevToolsAgent,
|
||||
} from '../Types/ReactDevToolsTypes';
|
||||
import type {HostRef} from './getInspectorDataForViewAtPoint';
|
||||
import type {InspectedElement} from './Inspector';
|
||||
|
||||
import View from '../Components/View/View';
|
||||
import ReactNativeFeatureFlags from '../ReactNative/ReactNativeFeatureFlags';
|
||||
@@ -37,9 +38,7 @@ export default function ReactDevToolsOverlay({
|
||||
inspectedView,
|
||||
reactDevToolsAgent,
|
||||
}: Props): React.Node {
|
||||
const [inspected, setInspected] = useState<null | {
|
||||
frame: {+height: any, +left: any, +top: any, +width: any},
|
||||
}>(null);
|
||||
const [inspected, setInspected] = useState<?InspectedElement>(null);
|
||||
const [isInspecting, setIsInspecting] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user