Skip to content

Commit

Permalink
Adding an optional wrapper component to app components
Browse files Browse the repository at this point in the history
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
  • Loading branch information
sumkit authored and facebook-github-bot committed Jun 26, 2017
1 parent 30352ec commit 162d92d
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 28 deletions.
38 changes: 26 additions & 12 deletions Libraries/ReactNative/AppContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule AppContainer
* @format
* @flow
*/

Expand All @@ -26,6 +27,7 @@ type Context = {
type Props = {
children?: React.Children,
rootTag: number,
WrapperComponent?: ?ReactClass<*>,
};
type State = {
inspector: ?React.Element<*>,
Expand Down Expand Up @@ -62,12 +64,13 @@ class AppContainer extends React.Component {
? null
: <Inspector
inspectedViewTag={ReactNative.findNodeHandle(this._mainRef)}
onRequestRerenderApp={(updateInspectedViewTag) => {
onRequestRerenderApp={updateInspectedViewTag => {
this.setState(
(s) => ({mainKey: s.mainKey + 1}),
() => updateInspectedViewTag(
ReactNative.findNodeHandle(this._mainRef)
)
s => ({mainKey: s.mainKey + 1}),
() =>
updateInspectedViewTag(
ReactNative.findNodeHandle(this._mainRef),
),
);
}}
/>;
Expand All @@ -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 (
<View style={styles.appContainer} pointerEvents="box-none">
<View
collapsable={!this.state.inspector}
key={this.state.mainKey}
pointerEvents="box-none"
style={styles.appContainer} ref={(ref) => {this._mainRef = ref;}}>
{this.props.children}
</View>
{innerView}
{yellowBox}
{this.state.inspector}
</View>
Expand Down
10 changes: 9 additions & 1 deletion Libraries/ReactNative/AppRegistry.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export type Registry = {
sections: Array<string>,
runnables: Runnables,
};
export type WrapperComponentProvider = any => ReactClass<*>;

const runnables: Runnables = {};
let runCount = 1;
Expand All @@ -51,6 +52,8 @@ const tasks: Map<string, TaskProvider> = new Map();
let componentProviderInstrumentationHook: ComponentProviderInstrumentationHook =
(component: ComponentProvider) => component();

let wrapperComponentProvider: ?WrapperComponentProvider;

/**
* <div class="banner-crna-ejected">
* <h3>Project with Native Code Required</h3>
Expand Down Expand Up @@ -78,6 +81,10 @@ let componentProviderInstrumentationHook: ComponentProviderInstrumentationHook =
* `require`d.
*/
const AppRegistry = {
setWrapperComponentProvider(provider: WrapperComponentProvider) {
wrapperComponentProvider = provider;
},

registerConfig(config: Array<AppConfig>): void {
config.forEach((appConfig) => {
if (appConfig.run) {
Expand Down Expand Up @@ -109,7 +116,8 @@ const AppRegistry = {
renderApplication(
componentProviderInstrumentationHook(componentProvider),
appParameters.initialProps,
appParameters.rootTag
appParameters.rootTag,
wrapperComponentProvider && wrapperComponentProvider(appParameters),
)
};
if (section) {
Expand Down
27 changes: 12 additions & 15 deletions Libraries/ReactNative/renderApplication.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,34 @@
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule renderApplication
* @format
* @flow
*/

'use strict';

var AppContainer = require('AppContainer');
var React = require('React');
var ReactNative = require('ReactNative');
const AppContainer = require('AppContainer');
const React = require('React');
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');

function renderApplication<Props: Object>(
RootComponent: ReactClass<Props>,
initialProps: Props,
rootTag: any
rootTag: any,
WrapperComponent?: ?ReactClass<*>,
) {
invariant(
rootTag,
'Expect to have a valid rootTag, instead got ', rootTag
);
invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag);

ReactNative.render(
<AppContainer rootTag={rootTag}>
<RootComponent
{...initialProps}
rootTag={rootTag}
/>
<AppContainer rootTag={rootTag} wrapperComponent={WrapperComponent}>
<RootComponent {...initialProps} rootTag={rootTag} />
</AppContainer>,
rootTag
rootTag,
);
}

Expand Down

1 comment on commit 162d92d

@shalleryu
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be used like createPortal in Reactjs, like create a Modal dialog in app root but with context from current component who use it

Please sign in to comment.