mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-24 12:25:59 +08:00
[ReactNative] Element Inspector
Summary:
This adds new development feature to React Native that provides information
about selected element (see the demo in Test Plan).
This is how it works:
App's root component is rendered to a container that also has a hidden layer called
`<InspectorOverlay/>`. When activated, it shows full screen view and captures all
touches. On every touch we ask UIManager to find a view for given {x,y} coordinates.
Then, we use React's internals to find corresponding React component. `setRootInstance`
is used to remember the top level component to start search from, lmk if you have a
better idea how to do this. Given a component, we can climb up its owners tree
to provice more context on how/where the component is used.
In future we could use the `hierarchy` array to inspect and print their props/state.
Known bugs and limitations:
* InspectorOverlay sometimes receives touches with incorrect coordinates (wtf)
* Not integrated with React Chrome Devtools (maybe in followup diffs)
* Doesn't work with popovers (maybe put the element inspector into an `<Overlay/>`?)
@public
Test Plan:
https://www.facebook.com/pxlcld/mn5k
Works nicely with scrollviews
This commit is contained in:
@@ -7,17 +7,59 @@
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule renderApplication
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var InspectorOverlay = require('InspectorOverlay');
|
||||
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
var React = require('React');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var Subscribable = require('Subscribable');
|
||||
var View = require('View');
|
||||
var WarningBox = require('WarningBox');
|
||||
|
||||
var invariant = require('invariant');
|
||||
|
||||
var AppContainer = React.createClass({
|
||||
mixins: [Subscribable.Mixin],
|
||||
|
||||
getInitialState: function() {
|
||||
return { inspector: null };
|
||||
},
|
||||
|
||||
toggleElementInspector: function() {
|
||||
var inspector = this.state.inspector
|
||||
? null
|
||||
: <InspectorOverlay
|
||||
rootTag={this.props.rootTag}
|
||||
inspectedViewTag={React.findNodeHandle(this.refs.main)}
|
||||
/>;
|
||||
this.setState({inspector});
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.addListenerOn(
|
||||
RCTDeviceEventEmitter,
|
||||
'toggleElementInspector',
|
||||
this.toggleElementInspector
|
||||
);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var shouldRenderWarningBox = __DEV__ && console.yellowBoxEnabled;
|
||||
var warningBox = shouldRenderWarningBox ? <WarningBox /> : null;
|
||||
return (
|
||||
<View style={styles.appContainer}>
|
||||
<View style={styles.appContainer} ref="main">
|
||||
{this.props.children}
|
||||
</View>
|
||||
{warningBox}
|
||||
{this.state.inspector}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
function renderApplication<D, P, S>(
|
||||
RootComponent: ReactClass<D, P, S>,
|
||||
initialProps: P,
|
||||
@@ -27,15 +69,12 @@ function renderApplication<D, P, S>(
|
||||
rootTag,
|
||||
'Expect to have a valid rootTag, instead got ', rootTag
|
||||
);
|
||||
var shouldRenderWarningBox = __DEV__ && console.yellowBoxEnabled;
|
||||
var warningBox = shouldRenderWarningBox ? <WarningBox /> : null;
|
||||
React.render(
|
||||
<View style={styles.appContainer}>
|
||||
<AppContainer rootTag={rootTag}>
|
||||
<RootComponent
|
||||
{...initialProps}
|
||||
/>
|
||||
{warningBox}
|
||||
</View>,
|
||||
</AppContainer>,
|
||||
rootTag
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user