[add] AppRegistry provider methods

Adds support for the following methods in React Native:
- setComponentProviderInstrumentationHook
- setWrapperComponentProvider
This commit is contained in:
Nicolas Gallagher
2018-04-01 10:26:17 -07:00
parent a9cacb2ef5
commit b96dd668d3
5 changed files with 96 additions and 43 deletions
@@ -11,13 +11,14 @@
import StyleSheet from '../StyleSheet'; import StyleSheet from '../StyleSheet';
import View from '../View'; import View from '../View';
import { any, node } from 'prop-types'; import { any, node } from 'prop-types';
import React, { Component } from 'react'; import React, { Component, type ComponentType } from 'react';
type Context = { type Context = {
rootTag: any rootTag: any
}; };
type Props = { type Props = {
WrapperComponent?: ?ComponentType<*>,
// $FlowFixMe // $FlowFixMe
children?: React.Children, children?: React.Children,
rootTag: any rootTag: any
@@ -35,6 +36,7 @@ export default class AppContainer extends Component<Props, State> {
}; };
static propTypes = { static propTypes = {
WrapperComponent: any,
children: node, children: node,
rootTag: any.isRequired rootTag: any.isRequired
}; };
@@ -46,14 +48,23 @@ export default class AppContainer extends Component<Props, State> {
} }
render() { render() {
const { children, WrapperComponent } = this.props;
let innerView = (
<View
children={children}
key={this.state.mainKey}
pointerEvents="box-none"
style={styles.appContainer}
/>
);
if (WrapperComponent) {
innerView = <WrapperComponent>{innerView}</WrapperComponent>;
}
return ( return (
<View pointerEvents="box-none" style={styles.appContainer}> <View pointerEvents="box-none" style={styles.appContainer}>
<View {innerView}
children={this.props.children}
key={this.state.mainKey}
pointerEvents="box-none"
style={styles.appContainer}
/>
</View> </View>
); );
} }
@@ -11,6 +11,7 @@ exports[`Additional CSS for styled app 1`] = `
exports[`AppRegistry/renderApplication getApplication returns "element" and "getStyleElement" 1`] = ` exports[`AppRegistry/renderApplication getApplication returns "element" and "getStyleElement" 1`] = `
<AppContainer <AppContainer
WrapperComponent={undefined}
rootTag={Object {}} rootTag={Object {}}
> >
<RootComponent /> <RootComponent />
+31 -5
View File
@@ -18,6 +18,15 @@ const emptyObject = {};
const runnables = {}; const runnables = {};
export type ComponentProvider = () => ComponentType<any>; export type ComponentProvider = () => ComponentType<any>;
export type ComponentProviderInstrumentationHook = (
component: ComponentProvider
) => ComponentType<any>;
export type WrapperComponentProvider = any => ComponentType<*>;
let componentProviderInstrumentationHook: ComponentProviderInstrumentationHook = (
component: ComponentProvider
) => component();
let wrapperComponentProvider: ?WrapperComponentProvider;
export type AppConfig = { export type AppConfig = {
appKey: string, appKey: string,
@@ -44,12 +53,21 @@ export default class AppRegistry {
return runnables[appKey].getApplication(appParameters); return runnables[appKey].getApplication(appParameters);
} }
static registerComponent(appKey: string, getComponentFunc: ComponentProvider): string { static registerComponent(appKey: string, componentProvider: ComponentProvider): string {
runnables[appKey] = { runnables[appKey] = {
getApplication: ({ initialProps } = emptyObject) => getApplication: appParameters =>
getApplication(getComponentFunc(), initialProps), getApplication(
run: ({ initialProps = emptyObject, rootTag }) => componentProviderInstrumentationHook(componentProvider),
renderApplication(getComponentFunc(), initialProps, rootTag) appParameters.initialProps || emptyObject,
wrapperComponentProvider && wrapperComponentProvider(appParameters)
),
run: appParameters =>
renderApplication(
componentProviderInstrumentationHook(componentProvider),
appParameters.initialProps || emptyObject,
appParameters.rootTag,
wrapperComponentProvider && wrapperComponentProvider(appParameters)
)
}; };
return appKey; return appKey;
} }
@@ -91,6 +109,14 @@ export default class AppRegistry {
runnables[appKey].run(appParameters); runnables[appKey].run(appParameters);
} }
static setComponentProviderInstrumentationHook(hook: ComponentProviderInstrumentationHook) {
componentProviderInstrumentationHook = hook;
}
static setWrapperComponentProvider(provider: WrapperComponentProvider) {
wrapperComponentProvider = provider;
}
static unmountApplicationComponentAtRootTag(rootTag: Object) { static unmountApplicationComponentAtRootTag(rootTag: Object) {
unmountComponentAtNode(rootTag); unmountComponentAtNode(rootTag);
} }
@@ -20,21 +20,26 @@ const renderFn = process.env.NODE_ENV !== 'production' ? render : hydrate;
export default function renderApplication<Props: Object>( export default function renderApplication<Props: Object>(
RootComponent: ComponentType<Props>, RootComponent: ComponentType<Props>,
initialProps: Props, initialProps: Props,
rootTag: any rootTag: any,
WrapperComponent?: ?ComponentType<*>
) { ) {
invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag); invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag);
renderFn( renderFn(
<AppContainer rootTag={rootTag}> <AppContainer WrapperComponent={WrapperComponent} rootTag={rootTag}>
<RootComponent {...initialProps} /> <RootComponent {...initialProps} />
</AppContainer>, </AppContainer>,
rootTag rootTag
); );
} }
export function getApplication(RootComponent: ComponentType<Object>, initialProps: Object): Object { export function getApplication(
RootComponent: ComponentType<Object>,
initialProps: Object,
WrapperComponent?: ?ComponentType<*>
): Object {
const element = ( const element = (
<AppContainer rootTag={{}}> <AppContainer WrapperComponent={WrapperComponent} rootTag={{}}>
<RootComponent {...initialProps} /> <RootComponent {...initialProps} />
</AppContainer> </AppContainer>
); );
@@ -19,11 +19,37 @@ const AppRegistryScreen = () => (
AppRegistry is the control point for registering, running, prerendering, and unmounting all AppRegistry is the control point for registering, running, prerendering, and unmounting all
apps. App root components should register themselves with{' '} apps. App root components should register themselves with{' '}
<Code>AppRegistry.registerComponent</Code>. Apps can be run by invoking{' '} <Code>AppRegistry.registerComponent</Code>. Apps can be run by invoking{' '}
<Code>AppRegistry.runApplication</Code> <Code>AppRegistry.runApplication</Code>.
</AppText> </AppText>
</Description> </Description>
<Section title="Methods"> <Section title="Methods">
<DocItem
description="Returns all registered app keys"
name="static getAppKeys"
typeInfo="() => Array<string>"
/>
<DocItem
description="Use this for server-side rendering to HTML. Returns a object of the given application's element, and a function to get styles once the element is rendered."
label="web"
name="static getApplication"
typeInfo="(appKey: string, appParameters: ?object) => { element: ReactElement; getStyleElement: () => ReactElement }"
/>
<DocItem
description={
<AppText>
Register a component provider under the given <Code>appKey</Code>.
</AppText>
}
example={{
code: 'AppRegistry.registerComponent("MyApp", () => AppComponent)'
}}
name="static registerComponent"
typeInfo="(appKey: string, getComponentFunc: ComponentProvider) => void"
/>
<DocItem <DocItem
description={[ description={[
<AppText> <AppText>
@@ -39,19 +65,6 @@ const AppRegistryScreen = () => (
typeInfo="(config: Array<AppConfig>) => avoid" typeInfo="(config: Array<AppConfig>) => avoid"
/> />
<DocItem
description={
<AppText>
Register a component provider under the given <Code>appKey</Code>.
</AppText>
}
example={{
code: 'AppRegistry.registerComponent("MyApp", () => AppComponent)'
}}
name="static registerComponent"
typeInfo="(appKey: string, getComponentFunc: ComponentProvider) => void"
/>
<DocItem <DocItem
description={ description={
<AppText> <AppText>
@@ -63,12 +76,6 @@ const AppRegistryScreen = () => (
typeInfo="(appKey: string, run: Function) => void" typeInfo="(appKey: string, run: Function) => void"
/> />
<DocItem
description="Returns all registered app keys"
name="static getAppKeys"
typeInfo="() => Array<string>"
/>
<DocItem <DocItem
description={ description={
<AppText> <AppText>
@@ -87,6 +94,16 @@ const AppRegistryScreen = () => (
typeInfo="(appKey: string, appParameters?: object) => void" typeInfo="(appKey: string, appParameters?: object) => void"
/> />
<DocItem
name="static setComponentProviderInstrumentationHook"
typeInfo="(componentProvider: func) => Component"
/>
<DocItem
name="static setWrapperComponentProvider"
typeInfo="(appParameters: object) => Component"
/>
<DocItem <DocItem
description={ description={
<AppText> <AppText>
@@ -98,13 +115,6 @@ const AppRegistryScreen = () => (
name="static unmountApplicationComponentAtRootTag" name="static unmountApplicationComponentAtRootTag"
typeInfo="(rootTag: HTMLElement) => void" typeInfo="(rootTag: HTMLElement) => void"
/> />
<DocItem
description="Use this for server-side rendering to HTML. Returns a object of the given application's element, and a function to get styles once the element is rendered."
label="web"
name="static getApplication"
typeInfo="(appKey: string, appParameters: ?object) => { element: ReactElement; getStyleElement: () => ReactElement }"
/>
</Section> </Section>
</UIExplorer> </UIExplorer>
); );