Skip to content

Commit fb7fe2d

Browse files
fkgozaliFacebook Github Bot
authored andcommitted
modernize AppContainer and add rootTag in the child context
Summary: This does 2 things: - modernize the component to use ES6 + flow - assign `rootTag` to the child context Each view in RN has its own `reactTag`. The reactTag for a root view is called `rootTag`. When there are multiple react root views active within the app (e.g. in a hybrid environment), rootTag is the only reliable "label" to differentiate them. This is especially useful when we want to limit an event/activity on a particular root view, instead of affecting all active root views. This allows components to do: ``` class Foo extends React.Component { static contextTypes = { rootTag: React.PropTypes.number, }; componentDidMount() { // Get the root tag of this component, which is static for all components under the same root view console.log(this.context.rootTag); } } ``` In a pure JS RN app environment, there will always be exactly 1 root view, so `rootTag` may usually be ignored. Reviewed By: yungsters Differential Revision: D4130376 fbshipit-source-id: 559b67615f487bad754b5832ad4a02bcef05be2a
1 parent 6c04b35 commit fb7fe2d

File tree

2 files changed

+72
-40
lines changed

2 files changed

+72
-40
lines changed

Libraries/ReactNative/AppContainer.js

Lines changed: 71 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,72 +7,104 @@
77
* of patent rights can be found in the PATENTS file in the same directory.
88
*
99
* @providesModule AppContainer
10-
* @noflow
10+
* @flow
1111
*/
1212

1313
'use strict';
1414

15-
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
16-
var React = require('React');
17-
var ReactNative = require('ReactNative');
18-
var StyleSheet = require('StyleSheet');
19-
var Subscribable = require('Subscribable');
20-
var View = require('View');
15+
const EmitterSubscription = require('EmitterSubscription');
16+
const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
17+
const React = require('React');
18+
const ReactNative = require('ReactNative');
19+
const StyleSheet = require('StyleSheet');
20+
const View = require('View');
2121

22-
var Inspector = __DEV__ ? require('Inspector') : null;
23-
var YellowBox = __DEV__ ? require('YellowBox') : null;
22+
// TODO (fkg): make rootTag required
23+
type Context = {
24+
rootTag: ?number,
25+
};
26+
type Props = {
27+
children?: React.Children,
28+
rootTag?: number,
29+
};
30+
type State = {
31+
inspector: ?React.Element<*>,
32+
mainKey: number,
33+
};
2434

25-
var AppContainer = React.createClass({
26-
mixins: [Subscribable.Mixin],
35+
class AppContainer extends React.Component {
36+
props: Props;
37+
state: State = {
38+
inspector: null,
39+
mainKey: 1,
40+
};
41+
_mainRef: ?React.Element<*>;
42+
_subscription: ?EmitterSubscription = null;
2743

28-
getInitialState: function() {
29-
return { inspector: null, mainKey: 1 };
30-
},
44+
static childContextTypes = {
45+
rootTag: React.PropTypes.number,
46+
};
3147

32-
toggleElementInspector: function() {
33-
var inspector = !__DEV__ || this.state.inspector
34-
? null
35-
: <Inspector
36-
inspectedViewTag={ReactNative.findNodeHandle(this.refs.main)}
37-
onRequestRerenderApp={(updateInspectedViewTag) => {
38-
this.setState(
39-
(s) => ({mainKey: s.mainKey + 1}),
40-
() => updateInspectedViewTag(ReactNative.findNodeHandle(this.refs.main))
41-
);
42-
}}
43-
/>;
44-
this.setState({inspector});
45-
},
48+
getChildContext(): Context {
49+
return {
50+
rootTag: this.props.rootTag,
51+
};
52+
}
4653

47-
componentDidMount: function() {
48-
this.addListenerOn(
49-
RCTDeviceEventEmitter,
50-
'toggleElementInspector',
51-
this.toggleElementInspector
52-
);
53-
},
54+
componentDidMount(): void {
55+
if (__DEV__) {
56+
this._subscription = RCTDeviceEventEmitter.addListener(
57+
'toggleElementInspector',
58+
() => {
59+
const Inspector = require('Inspector');
60+
const inspector = this.state.inspector
61+
? null
62+
: <Inspector
63+
inspectedViewTag={ReactNative.findNodeHandle(this._mainRef)}
64+
onRequestRerenderApp={(updateInspectedViewTag) => {
65+
this.setState(
66+
(s) => ({mainKey: s.mainKey + 1}),
67+
() => updateInspectedViewTag(
68+
ReactNative.findNodeHandle(this._mainRef)
69+
)
70+
);
71+
}}
72+
/>;
73+
this.setState({inspector});
74+
},
75+
);
76+
}
77+
}
78+
79+
componentWillUnmount(): void {
80+
if (this._subscription) {
81+
this._subscription.remove();
82+
}
83+
}
5484

55-
render: function() {
85+
render(): React.Element<*> {
5686
let yellowBox = null;
5787
if (__DEV__) {
88+
const YellowBox = require('YellowBox');
5889
yellowBox = <YellowBox />;
5990
}
91+
6092
return (
6193
<View style={styles.appContainer}>
6294
<View
6395
collapsable={!this.state.inspector}
6496
key={this.state.mainKey}
65-
style={styles.appContainer} ref="main">
97+
style={styles.appContainer} ref={(ref) => {this._mainRef = ref;}}>
6698
{this.props.children}
6799
</View>
68100
{yellowBox}
69101
{this.state.inspector}
70102
</View>
71103
);
72104
}
73-
});
105+
}
74106

75-
var styles = StyleSheet.create({
107+
const styles = StyleSheet.create({
76108
appContainer: {
77109
flex: 1,
78110
},

Libraries/ReactNative/renderApplication.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ function renderApplication<Props>(
3131
'Expect to have a valid rootTag, instead got ', rootTag
3232
);
3333
ReactNative.render(
34-
<AppContainer>
34+
<AppContainer rootTag={rootTag}>
3535
<RootComponent
3636
{...initialProps}
3737
rootTag={rootTag}

0 commit comments

Comments
 (0)