Adding an optional wrapper component to app components

Summary: Changing AppContainer to render a wrapper component in it, if it exists. This wrapper is NOT a required property of AppContainer. Now, app-wide properties can be passed down via context to the container's children.

Reviewed By: sahrens, fkgozali

Differential Revision: D5283895

fbshipit-source-id: 8595e22c4b5ebf5d0e57f358152fba8a80cb2723
This commit is contained in:
Summer Kitahara
2017-06-26 16:20:39 -07:00
committed by Facebook Github Bot
parent 30352ecbf2
commit 162d92da0e
3 changed files with 47 additions and 28 deletions

View File

@@ -7,6 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
* *
* @providesModule AppContainer * @providesModule AppContainer
* @format
* @flow * @flow
*/ */
@@ -26,6 +27,7 @@ type Context = {
type Props = { type Props = {
children?: React.Children, children?: React.Children,
rootTag: number, rootTag: number,
WrapperComponent?: ?ReactClass<*>,
}; };
type State = { type State = {
inspector: ?React.Element<*>, inspector: ?React.Element<*>,
@@ -62,12 +64,13 @@ class AppContainer extends React.Component {
? null ? null
: <Inspector : <Inspector
inspectedViewTag={ReactNative.findNodeHandle(this._mainRef)} inspectedViewTag={ReactNative.findNodeHandle(this._mainRef)}
onRequestRerenderApp={(updateInspectedViewTag) => { onRequestRerenderApp={updateInspectedViewTag => {
this.setState( this.setState(
(s) => ({mainKey: s.mainKey + 1}), s => ({mainKey: s.mainKey + 1}),
() => updateInspectedViewTag( () =>
ReactNative.findNodeHandle(this._mainRef) updateInspectedViewTag(
) ReactNative.findNodeHandle(this._mainRef),
),
); );
}} }}
/>; />;
@@ -93,15 +96,26 @@ class AppContainer extends React.Component {
} }
} }
let innerView = (
<View
collapsable={!this.state.inspector}
key={this.state.mainKey}
pointerEvents="box-none"
style={styles.appContainer}
ref={ref => {
this._mainRef = ref;
}}>
{this.props.children}
</View>
);
const Wrapper = this.props.WrapperComponent;
if (Wrapper) {
innerView = <Wrapper>{innerView}</Wrapper>;
}
return ( return (
<View style={styles.appContainer} pointerEvents="box-none"> <View style={styles.appContainer} pointerEvents="box-none">
<View {innerView}
collapsable={!this.state.inspector}
key={this.state.mainKey}
pointerEvents="box-none"
style={styles.appContainer} ref={(ref) => {this._mainRef = ref;}}>
{this.props.children}
</View>
{yellowBox} {yellowBox}
{this.state.inspector} {this.state.inspector}
</View> </View>

View File

@@ -43,6 +43,7 @@ export type Registry = {
sections: Array<string>, sections: Array<string>,
runnables: Runnables, runnables: Runnables,
}; };
export type WrapperComponentProvider = any => ReactClass<*>;
const runnables: Runnables = {}; const runnables: Runnables = {};
let runCount = 1; let runCount = 1;
@@ -51,6 +52,8 @@ const tasks: Map<string, TaskProvider> = new Map();
let componentProviderInstrumentationHook: ComponentProviderInstrumentationHook = let componentProviderInstrumentationHook: ComponentProviderInstrumentationHook =
(component: ComponentProvider) => component(); (component: ComponentProvider) => component();
let wrapperComponentProvider: ?WrapperComponentProvider;
/** /**
* <div class="banner-crna-ejected"> * <div class="banner-crna-ejected">
* <h3>Project with Native Code Required</h3> * <h3>Project with Native Code Required</h3>
@@ -78,6 +81,10 @@ let componentProviderInstrumentationHook: ComponentProviderInstrumentationHook =
* `require`d. * `require`d.
*/ */
const AppRegistry = { const AppRegistry = {
setWrapperComponentProvider(provider: WrapperComponentProvider) {
wrapperComponentProvider = provider;
},
registerConfig(config: Array<AppConfig>): void { registerConfig(config: Array<AppConfig>): void {
config.forEach((appConfig) => { config.forEach((appConfig) => {
if (appConfig.run) { if (appConfig.run) {
@@ -109,7 +116,8 @@ const AppRegistry = {
renderApplication( renderApplication(
componentProviderInstrumentationHook(componentProvider), componentProviderInstrumentationHook(componentProvider),
appParameters.initialProps, appParameters.initialProps,
appParameters.rootTag appParameters.rootTag,
wrapperComponentProvider && wrapperComponentProvider(appParameters),
) )
}; };
if (section) { if (section) {

View File

@@ -7,16 +7,17 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
* *
* @providesModule renderApplication * @providesModule renderApplication
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
var AppContainer = require('AppContainer'); const AppContainer = require('AppContainer');
var React = require('React'); const React = require('React');
var ReactNative = require('ReactNative'); const ReactNative = require('ReactNative');
var invariant = require('fbjs/lib/invariant'); const invariant = require('fbjs/lib/invariant');
// require BackHandler so it sets the default handler that exits the app if no listeners respond // require BackHandler so it sets the default handler that exits the app if no listeners respond
require('BackHandler'); require('BackHandler');
@@ -24,20 +25,16 @@ require('BackHandler');
function renderApplication<Props: Object>( function renderApplication<Props: Object>(
RootComponent: ReactClass<Props>, RootComponent: ReactClass<Props>,
initialProps: Props, initialProps: Props,
rootTag: any rootTag: any,
WrapperComponent?: ?ReactClass<*>,
) { ) {
invariant( invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag);
rootTag,
'Expect to have a valid rootTag, instead got ', rootTag
);
ReactNative.render( ReactNative.render(
<AppContainer rootTag={rootTag}> <AppContainer rootTag={rootTag} wrapperComponent={WrapperComponent}>
<RootComponent <RootComponent {...initialProps} rootTag={rootTag} />
{...initialProps}
rootTag={rootTag}
/>
</AppContainer>, </AppContainer>,
rootTag rootTag,
); );
} }