Saúl Ibarra Corretgé 6e679f952f redux: refactor loading of middlewares and reducers
Up until now we relied on implicit loading of middlewares and reducers, through
having imports in each feature's index.js.

This leads to many complex import cycles which result in (sometimes) hard to fix
bugs in addition to (often) breaking mobile because a web-only feature gets
imported on mobile too, thanks to the implicit loading.

This PR changes that to make the process explicit. Both middlewares and reducers
are imported in a single place, the app entrypoint. They have been divided into
3 categories: any, web and native, which represent each of the platforms
  respectively.

Ideally no feature should have an index.js exporting actions, action types and
components, but that's a larger ordeal, so this is just the first step in
getting there. In order to both set example and avoid large cycles the app
feature has been refactored to not have an idex.js itself.
2020-06-16 11:24:15 +02:00

116 lines
3.0 KiB
JavaScript

// @flow
import React, { Fragment } from 'react';
import { BaseApp } from '../../base/app';
import { toURLString } from '../../base/util';
import { OverlayContainer } from '../../overlay';
import { appNavigate } from '../actions';
import { getDefaultURL } from '../functions';
/**
* The type of React {@code Component} props of {@link AbstractApp}.
*/
export type Props = {
/**
* XXX Refer to the implementation of loadURLObject: in
* ios/sdk/src/JitsiMeetView.m for further information.
*/
timestamp: any,
/**
* The URL, if any, with which the app was launched.
*/
url: Object | string
};
/**
* Base (abstract) class for main App component.
*
* @abstract
*/
export class AbstractApp extends BaseApp<Props, *> {
_init: Promise<*>;
/**
* Initializes the app.
*
* @inheritdoc
*/
componentDidMount() {
super.componentDidMount();
this._init.then(() => {
// If a URL was explicitly specified to this React Component, then
// open it; otherwise, use a default.
this._openURL(toURLString(this.props.url) || this._getDefaultURL());
});
}
/**
* Implements React Component's componentDidUpdate.
*
* @inheritdoc
*/
componentDidUpdate(prevProps: Props) {
const previousUrl = toURLString(prevProps.url);
const currentUrl = toURLString(this.props.url);
const previousTimestamp = prevProps.timestamp;
const currentTimestamp = this.props.timestamp;
this._init.then(() => {
// Deal with URL changes.
if (previousUrl !== currentUrl
// XXX Refer to the implementation of loadURLObject: in
// ios/sdk/src/JitsiMeetView.m for further information.
|| previousTimestamp !== currentTimestamp) {
this._openURL(currentUrl || this._getDefaultURL());
}
});
}
/**
* Creates an extra {@link ReactElement}s to be added (unconditionaly)
* alongside the main element.
*
* @abstract
* @protected
* @returns {ReactElement}
*/
_createExtraElement() {
return (
<Fragment>
<OverlayContainer />
</Fragment>
);
}
_createMainElement: (React$Element<*>, Object) => ?React$Element<*>;
/**
* Gets the default URL to be opened when this {@code App} mounts.
*
* @protected
* @returns {string} The default URL to be opened when this {@code App}
* mounts.
*/
_getDefaultURL() {
return getDefaultURL(this.state.store);
}
/**
* Navigates this {@code AbstractApp} to (i.e. Opens) a specific URL.
*
* @param {Object|string} url - The URL to navigate this {@code AbstractApp}
* to (i.e. The URL to open).
* @protected
* @returns {void}
*/
_openURL(url) {
this.state.store.dispatch(appNavigate(toURLString(url)));
}
}