modernize AppRegistry.js and introduce app-specific 'sections'

Summary:
Simple cleanup for AppRegistry.

Also added `registerSection()` helper to mark registered components as app-specific sections. Sections can be treated in many custom ways, e.g. they could just indicate the top level tabs, or something else. A bunch of helpers are also added.

Reviewed By: yungsters

Differential Revision: D4542788

fbshipit-source-id: 07addecb78a7514e973335bca24414fd8db40997
This commit is contained in:
Kevin Gozali 2017-02-10 12:38:50 -08:00 committed by Facebook Github Bot
parent 6f2544a16b
commit c7c3e4c5d8
1 changed files with 68 additions and 27 deletions

View File

@ -11,13 +11,13 @@
*/ */
'use strict'; 'use strict';
var BatchedBridge = require('BatchedBridge'); const BatchedBridge = require('BatchedBridge');
var BugReporting = require('BugReporting'); const BugReporting = require('BugReporting');
var ReactNative = require('ReactNative'); const ReactNative = require('ReactNative');
const infoLog = require('infoLog'); const infoLog = require('infoLog');
var invariant = require('fbjs/lib/invariant'); const invariant = require('fbjs/lib/invariant');
var renderApplication = require('renderApplication'); const renderApplication = require('renderApplication');
const { HeadlessJsTaskSupport } = require('NativeModules'); const { HeadlessJsTaskSupport } = require('NativeModules');
@ -29,18 +29,25 @@ if (__DEV__) {
type Task = (taskData: any) => Promise<void>; type Task = (taskData: any) => Promise<void>;
type TaskProvider = () => Task; type TaskProvider = () => Task;
var runnables = {};
var runCount = 1;
const tasks: Map<string, TaskProvider> = new Map();
type ComponentProvider = () => ReactClass<any>; type ComponentProvider = () => ReactClass<any>;
type AppConfig = { type AppConfig = {
appKey: string, appKey: string,
component?: ComponentProvider, component?: ComponentProvider,
run?: Function, run?: Function,
section?: boolean,
}; };
type Runnable = {
component?: ComponentProvider,
run: Function,
};
type Runnables = {
[appKey: string]: Runnable,
};
const runnables: Runnables = {};
let runCount = 1;
const sections: Runnables = {};
const tasks: Map<string, TaskProvider> = new Map();
/** /**
* `AppRegistry` is the JS entry point to running all React Native apps. App * `AppRegistry` is the JS entry point to running all React Native apps. App
@ -57,37 +64,71 @@ type AppConfig = {
* sure the JS execution environment is setup before other modules are * sure the JS execution environment is setup before other modules are
* `require`d. * `require`d.
*/ */
var AppRegistry = { const AppRegistry = {
registerConfig: function(config: Array<AppConfig>) { registerConfig(config: Array<AppConfig>): void {
for (var i = 0; i < config.length; ++i) { config.forEach((appConfig) => {
var appConfig = config[i];
if (appConfig.run) { if (appConfig.run) {
AppRegistry.registerRunnable(appConfig.appKey, appConfig.run); AppRegistry.registerRunnable(appConfig.appKey, appConfig.run);
} else { } else {
invariant(appConfig.component, 'No component provider passed in'); invariant(
AppRegistry.registerComponent(appConfig.appKey, appConfig.component); appConfig.component != null,
'AppRegistry.registerConfig(...): Every config is expected to set ' +
'either `run` or `component`, but `%s` has neither.',
appConfig.appKey
);
AppRegistry.registerComponent(
appConfig.appKey,
appConfig.component,
appConfig.section,
);
} }
} });
}, },
registerComponent: function(appKey: string, getComponentFunc: ComponentProvider): string { registerComponent(
appKey: string,
component: ComponentProvider,
section?: boolean,
): string {
runnables[appKey] = { runnables[appKey] = {
component,
run: (appParameters) => run: (appParameters) =>
renderApplication(getComponentFunc(), appParameters.initialProps, appParameters.rootTag) renderApplication(component(), appParameters.initialProps, appParameters.rootTag)
}; };
if (section) {
sections[appKey] = runnables[appKey];
}
return appKey; return appKey;
}, },
registerRunnable: function(appKey: string, func: Function): string { registerRunnable(appKey: string, run: Function): string {
runnables[appKey] = {run: func}; runnables[appKey] = {run};
return appKey; return appKey;
}, },
getAppKeys: function(): Array<string> { registerSection(appKey: string, component: ComponentProvider): void {
AppRegistry.registerComponent(appKey, component, true);
},
getAppKeys(): Array<string> {
return Object.keys(runnables); return Object.keys(runnables);
}, },
runApplication: function(appKey: string, appParameters: any): void { getSectionKeys(): Array<string> {
return Object.keys(sections);
},
getSections(): Runnables {
return {
...sections
};
},
getRunnable(appKey: string): ?Runnable {
return runnables[appKey];
},
runApplication(appKey: string, appParameters: any): void {
const msg = const msg =
'Running application "' + appKey + '" with appParams: ' + 'Running application "' + appKey + '" with appParams: ' +
JSON.stringify(appParameters) + '. ' + JSON.stringify(appParameters) + '. ' +
@ -105,7 +146,7 @@ var AppRegistry = {
runnables[appKey].run(appParameters); runnables[appKey].run(appParameters);
}, },
unmountApplicationComponentAtRootTag: function(rootTag : number) { unmountApplicationComponentAtRootTag(rootTag: number): void {
ReactNative.unmountComponentAtNodeAndRemoveContainer(rootTag); ReactNative.unmountComponentAtNodeAndRemoveContainer(rootTag);
}, },
@ -116,7 +157,7 @@ var AppRegistry = {
* the only argument; when the promise is resolved or rejected the native side is * the only argument; when the promise is resolved or rejected the native side is
* notified of this event and it may decide to destroy the JS context. * notified of this event and it may decide to destroy the JS context.
*/ */
registerHeadlessTask: function(taskKey: string, task: TaskProvider): void { registerHeadlessTask(taskKey: string, task: TaskProvider): void {
if (tasks.has(taskKey)) { if (tasks.has(taskKey)) {
console.warn(`registerHeadlessTask called multiple times for same key '${taskKey}'`); console.warn(`registerHeadlessTask called multiple times for same key '${taskKey}'`);
} }
@ -130,7 +171,7 @@ var AppRegistry = {
* @param taskKey the key for the task to start * @param taskKey the key for the task to start
* @param data the data to pass to the task * @param data the data to pass to the task
*/ */
startHeadlessTask: function(taskId: number, taskKey: string, data: any): void { startHeadlessTask(taskId: number, taskKey: string, data: any): void {
const taskProvider = tasks.get(taskKey); const taskProvider = tasks.get(taskKey);
if (!taskProvider) { if (!taskProvider) {
throw new Error(`No task registered for key ${taskKey}`); throw new Error(`No task registered for key ${taskKey}`);