mirror of
https://github.com/status-im/react-native.git
synced 2025-02-09 16:14:47 +00:00
Refactor of Fiber integration with React Fiber + Stack
Summary: This PR aims to update the Inspector tool in React Native to use the new inspection APIs that have been added to the ReactNative renderer: https://github.com/facebook/react/pull/9691 This PR also cleans up the code in `Inspector.js` so there's no usage of React's internals. Closes https://github.com/facebook/react-native/pull/14160 Reviewed By: bvaughn Differential Revision: D5129280 Pulled By: trueadm fbshipit-source-id: b1b077c04f46b0f52cdea0e19b4154441558f77a
This commit is contained in:
parent
da50811609
commit
59e41b4485
@ -12,8 +12,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const BoxInspector = require('BoxInspector');
|
const BoxInspector = require('BoxInspector');
|
||||||
const React = require('React');
|
|
||||||
const PropTypes = require('prop-types');
|
const PropTypes = require('prop-types');
|
||||||
|
const React = require('React');
|
||||||
const StyleInspector = require('StyleInspector');
|
const StyleInspector = require('StyleInspector');
|
||||||
const StyleSheet = require('StyleSheet');
|
const StyleSheet = require('StyleSheet');
|
||||||
const Text = require('Text');
|
const Text = require('Text');
|
||||||
@ -76,14 +76,14 @@ class ElementProperties extends React.Component {
|
|||||||
<View style={styles.breadcrumb}>
|
<View style={styles.breadcrumb}>
|
||||||
{mapWithSeparator(
|
{mapWithSeparator(
|
||||||
this.props.hierarchy,
|
this.props.hierarchy,
|
||||||
(item, i) => (
|
(hierarchyItem, i) => (
|
||||||
<TouchableHighlight
|
<TouchableHighlight
|
||||||
key={'item-' + i}
|
key={'item-' + i}
|
||||||
style={[styles.breadItem, i === selection && styles.selected]}
|
style={[styles.breadItem, i === selection && styles.selected]}
|
||||||
// $FlowFixMe found when converting React.createClass to ES6
|
// $FlowFixMe found when converting React.createClass to ES6
|
||||||
onPress={() => this.props.setSelection(i)}>
|
onPress={() => this.props.setSelection(i)}>
|
||||||
<Text style={styles.breadItemText}>
|
<Text style={styles.breadItemText}>
|
||||||
{getInstanceName(item)}
|
{hierarchyItem.name}
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableHighlight>
|
</TouchableHighlight>
|
||||||
),
|
),
|
||||||
@ -109,16 +109,6 @@ class ElementProperties extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInstanceName(instance) {
|
|
||||||
if (instance.getName) {
|
|
||||||
return instance.getName();
|
|
||||||
}
|
|
||||||
if (instance.constructor && instance.constructor.displayName) {
|
|
||||||
return instance.constructor.displayName;
|
|
||||||
}
|
|
||||||
return 'Unknown';
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
breadSep: {
|
breadSep: {
|
||||||
fontSize: 8,
|
fontSize: 8,
|
||||||
|
@ -17,17 +17,31 @@
|
|||||||
const Dimensions = require('Dimensions');
|
const Dimensions = require('Dimensions');
|
||||||
const InspectorOverlay = require('InspectorOverlay');
|
const InspectorOverlay = require('InspectorOverlay');
|
||||||
const InspectorPanel = require('InspectorPanel');
|
const InspectorPanel = require('InspectorPanel');
|
||||||
const InspectorUtils = require('InspectorUtils');
|
|
||||||
const Platform = require('Platform');
|
const Platform = require('Platform');
|
||||||
const React = require('React');
|
const React = require('React');
|
||||||
|
const ReactNative = require('ReactNative');
|
||||||
const StyleSheet = require('StyleSheet');
|
const StyleSheet = require('StyleSheet');
|
||||||
const Touchable = require('Touchable');
|
const Touchable = require('Touchable');
|
||||||
const UIManager = require('UIManager');
|
const UIManager = require('UIManager');
|
||||||
const View = require('View');
|
const View = require('View');
|
||||||
|
|
||||||
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
|
const emptyObject = require('fbjs/lib/emptyObject');
|
||||||
// required for devtools to be able to edit react native styles
|
const invariant = require('invariant');
|
||||||
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.resolveRNStyle = require('flattenStyle');
|
|
||||||
|
export type ReactRenderer = {
|
||||||
|
getInspectorDataForViewTag: (viewTag: number) => Object,
|
||||||
|
};
|
||||||
|
|
||||||
|
const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
||||||
|
const renderer: ReactRenderer = findRenderer();
|
||||||
|
// required for devtools to be able to edit react native styles
|
||||||
|
hook.resolveRNStyle = require('flattenStyle');
|
||||||
|
|
||||||
|
function findRenderer(): ReactRenderer {
|
||||||
|
const renderers = hook._renderers;
|
||||||
|
const keys = Object.keys(renderers);
|
||||||
|
invariant(keys.length === 1, 'Expected to find exactly one React Native renderer on DevTools hook.');
|
||||||
|
return renderers[keys[0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
class Inspector extends React.Component {
|
class Inspector extends React.Component {
|
||||||
@ -67,13 +81,10 @@ class Inspector extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
|
hook.on('react-devtools', this.attachToDevtools);
|
||||||
(this : any).attachToDevtools = this.attachToDevtools.bind(this);
|
|
||||||
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.on('react-devtools', this.attachToDevtools);
|
|
||||||
// if devtools is already started
|
// if devtools is already started
|
||||||
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__.reactDevtoolsAgent) {
|
if (hook.reactDevtoolsAgent) {
|
||||||
this.attachToDevtools(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.reactDevtoolsAgent);
|
this.attachToDevtools(hook.reactDevtoolsAgent);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,9 +92,7 @@ class Inspector extends React.Component {
|
|||||||
if (this._subs) {
|
if (this._subs) {
|
||||||
this._subs.map(fn => fn());
|
this._subs.map(fn => fn());
|
||||||
}
|
}
|
||||||
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
|
hook.off('react-devtools', this.attachToDevtools);
|
||||||
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.off('react-devtools', this.attachToDevtools);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(newProps: Object) {
|
componentWillReceiveProps(newProps: Object) {
|
||||||
@ -94,12 +103,18 @@ class Inspector extends React.Component {
|
|||||||
let _hideWait = null;
|
let _hideWait = null;
|
||||||
const hlSub = agent.sub('highlight', ({node, name, props}) => {
|
const hlSub = agent.sub('highlight', ({node, name, props}) => {
|
||||||
clearTimeout(_hideWait);
|
clearTimeout(_hideWait);
|
||||||
|
|
||||||
|
if (typeof node !== 'number') {
|
||||||
|
// Fiber
|
||||||
|
node = ReactNative.findNodeHandle(node);
|
||||||
|
}
|
||||||
|
|
||||||
UIManager.measure(node, (x, y, width, height, left, top) => {
|
UIManager.measure(node, (x, y, width, height, left, top) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
hierarchy: [],
|
hierarchy: [],
|
||||||
inspected: {
|
inspected: {
|
||||||
frame: {left, top, width, height},
|
frame: {left, top, width, height},
|
||||||
style: props ? props.style : {},
|
style: props ? props.style : emptyObject,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -126,17 +141,21 @@ class Inspector extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
setSelection(i: number) {
|
setSelection(i: number) {
|
||||||
const instance = this.state.hierarchy[i];
|
const hierarchyItem = this.state.hierarchy[i];
|
||||||
// if we inspect a stateless component we can't use the getPublicInstance method
|
// we pass in ReactNative.findNodeHandle as the method is injected
|
||||||
// therefore we use the internal _instance property directly.
|
const {
|
||||||
const publicInstance = instance['_instance'] || {};
|
measure,
|
||||||
const source = instance['_currentElement'] && instance['_currentElement']['_source'];
|
props,
|
||||||
UIManager.measure(instance.getHostNode(), (x, y, width, height, left, top) => {
|
source,
|
||||||
|
} = hierarchyItem.getInspectorData(ReactNative.findNodeHandle);
|
||||||
|
|
||||||
|
measure((x, y, width, height, left, top) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
inspected: {
|
inspected: {
|
||||||
frame: {left, top, width, height},
|
frame: {left, top, width, height},
|
||||||
style: publicInstance.props ? publicInstance.props.style : {},
|
style: props.style,
|
||||||
source,
|
source,
|
||||||
},
|
},
|
||||||
selection: i,
|
selection: i,
|
||||||
@ -144,28 +163,28 @@ class Inspector extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onTouchInstance(touched: Object, frame: Object, pointerY: number) {
|
onTouchViewTag(touchedViewTag: number, frame: Object, pointerY: number) {
|
||||||
// Most likely the touched instance is a native wrapper (like RCTView)
|
// Most likely the touched instance is a native wrapper (like RCTView)
|
||||||
// which is not very interesting. Most likely user wants a composite
|
// which is not very interesting. Most likely user wants a composite
|
||||||
// instance that contains it (like View)
|
// instance that contains it (like View)
|
||||||
const hierarchy = InspectorUtils.getOwnerHierarchy(touched);
|
const {
|
||||||
const instance = InspectorUtils.lastNotNativeInstance(hierarchy);
|
hierarchy,
|
||||||
|
instance,
|
||||||
|
props,
|
||||||
|
selection,
|
||||||
|
source,
|
||||||
|
} = renderer.getInspectorDataForViewTag(touchedViewTag);
|
||||||
|
|
||||||
if (this.state.devtoolsAgent) {
|
if (this.state.devtoolsAgent) {
|
||||||
this.state.devtoolsAgent.selectFromReactInstance(instance, true);
|
this.state.devtoolsAgent.selectFromReactInstance(instance, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we inspect a stateless component we can't use the getPublicInstance method
|
|
||||||
// therefore we use the internal _instance property directly.
|
|
||||||
const publicInstance = instance['_instance'] || {};
|
|
||||||
const props = publicInstance.props || {};
|
|
||||||
const source = instance['_currentElement'] && instance['_currentElement']['_source'];
|
|
||||||
this.setState({
|
this.setState({
|
||||||
panelPos: pointerY > Dimensions.get('window').height / 2 ? 'top' : 'bottom',
|
panelPos: pointerY > Dimensions.get('window').height / 2 ? 'top' : 'bottom',
|
||||||
selection: hierarchy.indexOf(instance),
|
selection,
|
||||||
hierarchy,
|
hierarchy,
|
||||||
inspected: {
|
inspected: {
|
||||||
style: props.style || {},
|
style: props.style,
|
||||||
frame,
|
frame,
|
||||||
source,
|
source,
|
||||||
},
|
},
|
||||||
@ -214,7 +233,7 @@ class Inspector extends React.Component {
|
|||||||
<InspectorOverlay
|
<InspectorOverlay
|
||||||
inspected={this.state.inspected}
|
inspected={this.state.inspected}
|
||||||
inspectedViewTag={this.state.inspectedViewTag}
|
inspectedViewTag={this.state.inspectedViewTag}
|
||||||
onTouchInstance={this.onTouchInstance.bind(this)}
|
onTouchViewTag={this.onTouchViewTag.bind(this)}
|
||||||
/>}
|
/>}
|
||||||
<View style={[styles.panelContainer, panelContainerStyle]}>
|
<View style={[styles.panelContainer, panelContainerStyle]}>
|
||||||
<InspectorPanel
|
<InspectorPanel
|
||||||
|
@ -12,13 +12,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var Dimensions = require('Dimensions');
|
var Dimensions = require('Dimensions');
|
||||||
var InspectorUtils = require('InspectorUtils');
|
var ElementBox = require('ElementBox');
|
||||||
var React = require('React');
|
|
||||||
var PropTypes = require('prop-types');
|
var PropTypes = require('prop-types');
|
||||||
|
var React = require('React');
|
||||||
var StyleSheet = require('StyleSheet');
|
var StyleSheet = require('StyleSheet');
|
||||||
var UIManager = require('UIManager');
|
var UIManager = require('UIManager');
|
||||||
var View = require('View');
|
var View = require('View');
|
||||||
var ElementBox = require('ElementBox');
|
|
||||||
|
|
||||||
type EventLike = {
|
type EventLike = {
|
||||||
nativeEvent: Object,
|
nativeEvent: Object,
|
||||||
@ -31,7 +30,7 @@ class InspectorOverlay extends React.Component {
|
|||||||
style?: any,
|
style?: any,
|
||||||
},
|
},
|
||||||
inspectedViewTag?: number,
|
inspectedViewTag?: number,
|
||||||
onTouchInstance: Function,
|
onTouchViewTag: (tag: number, frame: Object, pointerY: number) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
@ -40,7 +39,7 @@ class InspectorOverlay extends React.Component {
|
|||||||
style: PropTypes.any,
|
style: PropTypes.any,
|
||||||
}),
|
}),
|
||||||
inspectedViewTag: PropTypes.number,
|
inspectedViewTag: PropTypes.number,
|
||||||
onTouchInstance: PropTypes.func.isRequired,
|
onTouchViewTag: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
findViewForTouchEvent = (e: EventLike) => {
|
findViewForTouchEvent = (e: EventLike) => {
|
||||||
@ -49,11 +48,7 @@ class InspectorOverlay extends React.Component {
|
|||||||
this.props.inspectedViewTag,
|
this.props.inspectedViewTag,
|
||||||
[locationX, locationY],
|
[locationX, locationY],
|
||||||
(nativeViewTag, left, top, width, height) => {
|
(nativeViewTag, left, top, width, height) => {
|
||||||
var instance = InspectorUtils.findInstanceByNativeTag(nativeViewTag);
|
this.props.onTouchViewTag(nativeViewTag, {left, top, width, height}, locationY);
|
||||||
if (!instance) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.props.onTouchInstance(instance, {left, top, width, height}, locationY);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2015-present, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
* @providesModule InspectorUtils
|
|
||||||
*/
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var ReactNativeComponentTree = require('ReactNativeComponentTree');
|
|
||||||
|
|
||||||
function traverseOwnerTreeUp(hierarchy, instance) {
|
|
||||||
if (instance) {
|
|
||||||
hierarchy.unshift(instance);
|
|
||||||
traverseOwnerTreeUp(hierarchy, instance._currentElement._owner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findInstanceByNativeTag(nativeTag) {
|
|
||||||
var instance = ReactNativeComponentTree.getInstanceFromNode(nativeTag);
|
|
||||||
if (!instance || typeof instance.tag === 'number') {
|
|
||||||
// TODO(sema): We've disabled the inspector when using Fiber. Fix #15953531
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getOwnerHierarchy(instance) {
|
|
||||||
var hierarchy = [];
|
|
||||||
traverseOwnerTreeUp(hierarchy, instance);
|
|
||||||
return hierarchy;
|
|
||||||
}
|
|
||||||
|
|
||||||
function lastNotNativeInstance(hierarchy) {
|
|
||||||
for (let i = hierarchy.length - 1; i > 1; i--) {
|
|
||||||
const instance = hierarchy[i];
|
|
||||||
if (!instance.viewConfig) {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hierarchy[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {findInstanceByNativeTag, getOwnerHierarchy, lastNotNativeInstance};
|
|
@ -2914,6 +2914,9 @@ ReactNativeBaseComponent.Mixin = {
|
|||||||
updatePayload && UIManager.updateView(this._rootNodeID, this.viewConfig.uiViewClassName, updatePayload),
|
updatePayload && UIManager.updateView(this._rootNodeID, this.viewConfig.uiViewClassName, updatePayload),
|
||||||
this.updateChildren(nextElement.props.children, transaction, context);
|
this.updateChildren(nextElement.props.children, transaction, context);
|
||||||
},
|
},
|
||||||
|
getName: function() {
|
||||||
|
return this.constructor.displayName || this.constructor.name || "Unknown";
|
||||||
|
},
|
||||||
getHostNode: function() {
|
getHostNode: function() {
|
||||||
return this._rootNodeID;
|
return this._rootNodeID;
|
||||||
},
|
},
|
||||||
|
@ -2406,6 +2406,9 @@ ReactNativeBaseComponent.Mixin = {
|
|||||||
updatePayload && UIManager.updateView(this._rootNodeID, this.viewConfig.uiViewClassName, updatePayload),
|
updatePayload && UIManager.updateView(this._rootNodeID, this.viewConfig.uiViewClassName, updatePayload),
|
||||||
this.updateChildren(nextElement.props.children, transaction, context);
|
this.updateChildren(nextElement.props.children, transaction, context);
|
||||||
},
|
},
|
||||||
|
getName: function() {
|
||||||
|
return this.constructor.displayName || this.constructor.name || "Unknown";
|
||||||
|
},
|
||||||
getHostNode: function() {
|
getHostNode: function() {
|
||||||
return this._rootNodeID;
|
return this._rootNodeID;
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user