feat(App): refactor App and split it into BaseApp and App (continued)

There doesn't seem to be a strong need for the initialized React
Component state in BaseApp so remove/delete it.
This commit is contained in:
Lyubo Marinov 2018-07-12 11:16:57 -05:00
parent dc246960df
commit bfdfb5321c
4 changed files with 55 additions and 73 deletions

View File

@ -10,7 +10,7 @@ import { appNavigate } from '../actions';
import { getDefaultURL } from '../functions'; import { getDefaultURL } from '../functions';
/** /**
* {@code AbstractApp} component's property types. * The type of React {@code Component} props of {@link AbstractApp}.
*/ */
export type Props = { export type Props = {
@ -49,8 +49,8 @@ export class AbstractApp extends BaseApp<Props, *> {
super.componentWillMount(); super.componentWillMount();
this._init.then(() => { this._init.then(() => {
// If a URL was explicitly specified to this React Component, // If a URL was explicitly specified to this React Component, then
// then open it; otherwise, use a default. // open it; otherwise, use a default.
this._openURL(toURLString(this.props.url) || this._getDefaultURL()); this._openURL(toURLString(this.props.url) || this._getDefaultURL());
}); });
} }
@ -102,9 +102,9 @@ export class AbstractApp extends BaseApp<Props, *> {
* Creates an extra {@link ReactElement}s to be added (unconditionaly) * Creates an extra {@link ReactElement}s to be added (unconditionaly)
* alongside the main element. * alongside the main element.
* *
* @returns {ReactElement}
* @abstract * @abstract
* @protected * @protected
* @returns {ReactElement}
*/ */
_createExtraElement() { _createExtraElement() {
return ( return (

View File

@ -27,46 +27,46 @@ import type { Props as AbstractAppProps } from './AbstractApp';
declare var __DEV__; declare var __DEV__;
/** /**
* App component's property types. * The type of React {@code Component} props of {@link App}.
*/ */
type Props = AbstractAppProps & { type Props = AbstractAppProps & {
/** /**
* Whether the add people feature is enabled or not. * Whether the add people feature is enabled.
*/ */
addPeopleEnabled: boolean, addPeopleEnabled: boolean,
/** /**
* Whether the dial-out feature is enabled or not. * Whether the dial-out feature is enabled.
*/ */
dialOutEnabled: boolean, dialOutEnabled: boolean,
/** /**
* Whether Picture-in-Picture is enabled. If {@code true}, a toolbar * Whether Picture-in-Picture is enabled. If {@code true}, a toolbar button
* button is rendered in the {@link Conference} view to afford entering * is rendered in the {@link Conference} view to afford entering
* Picture-in-Picture. * Picture-in-Picture.
*/ */
pictureInPictureEnabled: boolean, pictureInPictureEnabled: boolean,
/** /**
* Whether the Welcome page is enabled. If {@code true}, the Welcome * Whether the Welcome page is enabled. If {@code true}, the Welcome page is
* page is rendered when the {@link App} is not at a location (URL) * rendered when the {@link App} is not at a location (URL) identifying
* identifying a Jitsi Meet conference/room. * a Jitsi Meet conference/room.
*/ */
welcomePageEnabled: boolean welcomePageEnabled: boolean
}; };
/** /**
* Root application component. * Root app {@code Component} on mobile/React Native.
* *
* @extends AbstractApp * @extends AbstractApp
*/ */
export class App extends AbstractApp { export class App extends AbstractApp {
/** /**
* Initializes a new App instance. * Initializes a new {@code App} instance.
* *
* @param {Object} props - The read-only React Component props with which * @param {Props} props - The read-only React {@code Component} props with
* the new instance is to be initialized. * which the new instance is to be initialized.
*/ */
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
@ -76,8 +76,8 @@ export class App extends AbstractApp {
// In the Release configuration, React Native will (intentionally) throw // In the Release configuration, React Native will (intentionally) throw
// an unhandled JavascriptException for an unhandled JavaScript error. // an unhandled JavascriptException for an unhandled JavaScript error.
// This will effectively kill the application. In accord with the Web, // This will effectively kill the app. In accord with the Web, do not
// do not kill the application. // kill the app.
this._maybeDisableExceptionsManager(); this._maybeDisableExceptionsManager();
} }
@ -130,10 +130,9 @@ export class App extends AbstractApp {
* {@link ExceptionsManager#handleException} on platforms and in * {@link ExceptionsManager#handleException} on platforms and in
* configurations on/in which the use of the method in questions has been * configurations on/in which the use of the method in questions has been
* determined to be undesirable. For example, React Native will * determined to be undesirable. For example, React Native will
* (intentionally) throw an unhandled JavascriptException for an * (intentionally) throw an unhandled {@code JavascriptException} for an
* unhandled JavaScript error in the Release configuration. This will * unhandled JavaScript error in the Release configuration. This will
* effectively kill the application. In accord with the Web, do not kill the * effectively kill the app. In accord with the Web, do not kill the app.
* application.
* *
* @private * @private
* @returns {void} * @returns {void}
@ -148,9 +147,9 @@ export class App extends AbstractApp {
// A solution based on RTCSetFatalHandler was implemented on iOS and // A solution based on RTCSetFatalHandler was implemented on iOS and
// it is preferred because it is at a later step of the // it is preferred because it is at a later step of the
// error/exception handling and it is specific to fatal // error/exception handling and it is specific to fatal
// errors/exceptions which were observed to kill the application. // errors/exceptions which were observed to kill the app. The
// The solution implemented bellow was tested on Android only so it // solution implemented bellow was tested on Android only so it is
// is considered safest to use it there only. // considered safest to use it there only.
return; return;
} }
@ -167,10 +166,10 @@ export class App extends AbstractApp {
/** /**
* Notified by React's Linking API that a specific URL registered to be * Notified by React's Linking API that a specific URL registered to be
* handled by this App was activated. * handled by this app was activated.
* *
* @param {Object} event - The details of the notification/event. * @param {Object} event - The details of the notification/event.
* @param {string} event.url - The URL registered to be handled by this App * @param {string} event.url - The URL registered to be handled by this app
* which was activated. * which was activated.
* @private * @private
* @returns {void} * @returns {void}
@ -183,11 +182,11 @@ export class App extends AbstractApp {
/** /**
* Handles a (possibly unhandled) JavaScript error by preventing React Native * Handles a (possibly unhandled) JavaScript error by preventing React Native
* from converting a fatal error into an unhandled native exception which will * from converting a fatal error into an unhandled native exception which will
* kill the application. * kill the app.
* *
* @param {Error} error - The (possibly unhandled) JavaScript error to handle. * @param {Error} error - The (possibly unhandled) JavaScript error to handle.
* @param {boolean} fatal - True if the specified error is fatal; otherwise, * @param {boolean} fatal - If the specified error is fatal, {@code true};
* false. * otherwise, {@code false}.
* @private * @private
* @returns {void} * @returns {void}
*/ */
@ -195,12 +194,12 @@ function _handleException(error, fatal) {
if (fatal) { if (fatal) {
// In the Release configuration, React Native will (intentionally) throw // In the Release configuration, React Native will (intentionally) throw
// an unhandled JavascriptException for an unhandled JavaScript error. // an unhandled JavascriptException for an unhandled JavaScript error.
// This will effectively kill the application. In accord with the Web, // This will effectively kill the app. In accord with the Web, do not
// do not kill the application. // kill the app.
console.error(error); console.error(error);
} else { } else {
// Forward to the next globalHandler of ErrorUtils. // Forward to the next globalHandler of ErrorUtils.
const next = _handleException.next; const { next } = _handleException;
typeof next === 'function' && next(error, fatal); typeof next === 'function' && next(error, fatal);
} }

View File

@ -11,11 +11,21 @@ import '../../video-layout';
import { AbstractApp } from './AbstractApp'; import { AbstractApp } from './AbstractApp';
/** /**
* Root application component. * Root app {@code Component} on Web/React.
* *
* @extends AbstractApp * @extends AbstractApp
*/ */
export class App extends AbstractApp { export class App extends AbstractApp {
/**
* Gets a Location object from the window with information about the current
* location of the document.
*
* @inheritdoc
*/
getWindowLocation() {
return window.location;
}
/** /**
* Overrides the parent method to inject {@link AtlasKitThemeProvider} as * Overrides the parent method to inject {@link AtlasKitThemeProvider} as
* the top most component. * the top most component.
@ -29,14 +39,4 @@ export class App extends AbstractApp {
</AtlasKitThemeProvider> </AtlasKitThemeProvider>
); );
} }
/**
* Gets a Location object from the window with information about the current
* location of the document.
*
* @inheritdoc
*/
getWindowLocation() {
return window.location;
}
} }

View File

@ -20,21 +20,18 @@ import { appWillMount, appWillUnmount } from '../actions';
declare var APP: Object; declare var APP: Object;
/**
* The type of the React {@code Component} state of {@link BaseApp}.
*/
type State = { type State = {
/** /**
* The state of the »possible« async initialization of * The {@code Route} rendered by the {@code BaseApp}.
* the {@code BaseApp}.
*/
initialized: boolean,
/**
* The Route rendered by this {@code BaseApp}.
*/ */
route: Object, route: Object,
/** /**
* The redux store used by this {@code BaseApp}. * The redux store used by the {@code BaseApp}.
*/ */
store: Object store: Object
}; };
@ -57,7 +54,6 @@ export default class BaseApp extends Component<*, State> {
super(props); super(props);
this.state = { this.state = {
initialized: false,
route: {}, route: {},
// $FlowFixMe // $FlowFixMe
@ -65,9 +61,8 @@ export default class BaseApp extends Component<*, State> {
}; };
/** /**
* Make the mobile {@code BaseApp} wait until the * Make the mobile {@code BaseApp} wait until the {@code AsyncStorage}
* {@code AsyncStorage} implementation of {@code Storage} initializes * implementation of {@code Storage} initializes fully.
* fully.
* *
* @private * @private
* @see {@link #_initStorage} * @see {@link #_initStorage}
@ -83,32 +78,21 @@ export default class BaseApp extends Component<*, State> {
} }
/** /**
* Initialize the application. * Initializes the app.
* *
* @inheritdoc * @inheritdoc
*/ */
componentWillMount() { componentWillMount() {
this._init.then(() => { this._init.then(() => this.state.store.dispatch(appWillMount(this)));
const { dispatch } = this.state.store;
dispatch(appWillMount(this));
// We set the initialized state here and not in the constructor to
// make sure that {@code componentWillMount} gets invoked before
// the app tries to render the actual app content.
this.setState({ initialized: true });
});
} }
/** /**
* De-initialize the application. * De-initializes the app.
* *
* @inheritdoc * @inheritdoc
*/ */
componentWillUnmount() { componentWillUnmount() {
const { dispatch } = this.state.store; this.state.store.dispatch(appWillUnmount(this));
dispatch(appWillUnmount(this));
} }
/** /**
@ -133,10 +117,9 @@ export default class BaseApp extends Component<*, State> {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
render() { render() {
const { initialized, route, store } = this.state; const { route: { component }, store } = this.state;
const { component } = route;
if (initialized && component) { if (store && component) {
return ( return (
<I18nextProvider i18n = { i18next }> <I18nextProvider i18n = { i18next }>
<Provider store = { store }> <Provider store = { store }>