From 307e253276866b29bc1bb07c975c09cd5155d948 Mon Sep 17 00:00:00 2001 From: tmoldovan8x8 <62697631+tmoldovan8x8@users.noreply.github.com> Date: Fri, 7 Jan 2022 15:18:24 +0200 Subject: [PATCH] fix(rn, web) await initialisation before dispatching appWillMount --- react/features/app/components/AbstractApp.js | 32 ++++++------ react/features/app/components/App.native.js | 49 ++++++++++-------- react/features/base/app/components/BaseApp.js | 48 ++++++++++++------ .../components/IncomingCallApp.js | 30 ++++++----- .../features/prejoin/components/PrejoinApp.js | 50 +++++++++---------- 5 files changed, 114 insertions(+), 95 deletions(-) diff --git a/react/features/app/components/AbstractApp.js b/react/features/app/components/AbstractApp.js index 1a466a9aca..b7d39f30c0 100644 --- a/react/features/app/components/AbstractApp.js +++ b/react/features/app/components/AbstractApp.js @@ -38,14 +38,12 @@ export class AbstractApp extends BaseApp { * * @inheritdoc */ - componentDidMount() { - super.componentDidMount(); + async componentDidMount() { + await 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()); - }); + // 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()); } /** @@ -53,23 +51,23 @@ export class AbstractApp extends BaseApp { * * @inheritdoc */ - componentDidUpdate(prevProps: Props) { + async 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. + await this._init; - if (previousUrl !== currentUrl + // Deal with URL changes. - // XXX Refer to the implementation of loadURLObject: in - // ios/sdk/src/JitsiMeetView.m for further information. - || previousTimestamp !== currentTimestamp) { - this._openURL(currentUrl || this._getDefaultURL()); - } - }); + 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()); + } } /** diff --git a/react/features/app/components/App.native.js b/react/features/app/components/App.native.js index aee972e767..f569e65631 100644 --- a/react/features/app/components/App.native.js +++ b/react/features/app/components/App.native.js @@ -81,40 +81,45 @@ export class App extends AbstractApp { * * @returns {void} */ - componentDidMount() { - super.componentDidMount(); + async componentDidMount() { + await super.componentDidMount(); SplashScreen.hide(); + } - this._init.then(() => { - const { dispatch, getState } = this.state.store; + /** + * Initializes feature flags and updates settings. + * + * @returns {void} + */ + _extraInit() { + const { dispatch, getState } = this.state.store; - // We set these early enough so then we avoid any unnecessary re-renders. - dispatch(updateFlags(this.props.flags)); + // We set these early enough so then we avoid any unnecessary re-renders. + dispatch(updateFlags(this.props.flags)); - // Check if serverURL is configured externally and not allowed to change. - const serverURLChangeEnabled = getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true); + // Check if serverURL is configured externally and not allowed to change. + const serverURLChangeEnabled = getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true); - if (!serverURLChangeEnabled) { - // As serverURL is provided externally, so we push it to settings. - if (typeof this.props.url !== 'undefined') { - const { serverURL } = this.props.url; + if (!serverURLChangeEnabled) { + // As serverURL is provided externally, so we push it to settings. + if (typeof this.props.url !== 'undefined') { + const { serverURL } = this.props.url; - if (typeof serverURL !== 'undefined') { - dispatch(updateSettings({ serverURL })); - } + if (typeof serverURL !== 'undefined') { + dispatch(updateSettings({ serverURL })); } } + } - dispatch(updateSettings(this.props.userInfo || {})); + dispatch(updateSettings(this.props.userInfo || {})); - // Update settings with feature-flag. - const callIntegrationEnabled = this.props.flags[CALL_INTEGRATION_ENABLED]; + // Update settings with feature-flag. + const callIntegrationEnabled = this.props.flags[CALL_INTEGRATION_ENABLED]; - if (typeof callIntegrationEnabled !== 'undefined') { - dispatch(updateSettings({ disableCallIntegration: !callIntegrationEnabled })); - } - }); + if (typeof callIntegrationEnabled !== 'undefined') { + dispatch(updateSettings({ disableCallIntegration: !callIntegrationEnabled })); + } } /** diff --git a/react/features/base/app/components/BaseApp.js b/react/features/base/app/components/BaseApp.js index f34233f50d..5d09cd16d0 100644 --- a/react/features/base/app/components/BaseApp.js +++ b/react/features/base/app/components/BaseApp.js @@ -16,6 +16,7 @@ import { StateListenerRegistry } from '../../redux'; import { SoundCollection } from '../../sounds'; +import { createDeferred } from '../../util'; import { appWillMount, appWillUnmount } from '../actions'; import logger from '../logger'; @@ -43,7 +44,10 @@ type State = { * @abstract */ export default class BaseApp extends Component<*, State> { - _init: Promise<*>; + /** + * The deferred for the initialisation {{promise, resolve, reject}}. + */ + _init: Object; /** * Initializes a new {@code BaseApp} instance. @@ -64,8 +68,8 @@ export default class BaseApp extends Component<*, State> { * Initializes the app. * * @inheritdoc - */ - componentDidMount() { + */ + async componentDidMount() { /** * Make the mobile {@code BaseApp} wait until the {@code AsyncStorage} * implementation of {@code Storage} initializes fully. @@ -74,21 +78,28 @@ export default class BaseApp extends Component<*, State> { * @see {@link #_initStorage} * @type {Promise} */ - this._init = this._initStorage() - .catch(err => { - /* BaseApp should always initialize! */ - logger.error(err); - }) - .then(() => new Promise(resolve => { + this._init = createDeferred(); + + try { + await this._initStorage(); + + const setStatePromise = new Promise(resolve => { this.setState({ store: this._createStore() }, resolve); - })) - .then(() => this.state.store.dispatch(appWillMount(this))) - .catch(err => { - /* BaseApp should always initialize! */ - logger.error(err); }); + + await setStatePromise; + + await this._extraInit(); + } catch (err) { + /* BaseApp should always initialize! */ + logger.error(err); + } + + this.state.store.dispatch(appWillMount(this)); + + this._init.resolve(); } /** @@ -127,6 +138,15 @@ export default class BaseApp extends Component<*, State> { return _initializing || Promise.resolve(); } + /** + * Extra initialisation that subclasses might require. + * + * @returns {void} + */ + _extraInit() { + // To be implemented by subclass. + } + /** * Implements React's {@link Component#render()}. * diff --git a/react/features/mobile/incoming-call/components/IncomingCallApp.js b/react/features/mobile/incoming-call/components/IncomingCallApp.js index b15ab21013..75360c9563 100644 --- a/react/features/mobile/incoming-call/components/IncomingCallApp.js +++ b/react/features/mobile/incoming-call/components/IncomingCallApp.js @@ -43,24 +43,22 @@ export default class IncomingCallApp extends BaseApp { * * @returns {void} */ - componentDidMount() { - super.componentDidMount(); + async componentDidMount() { + await super.componentDidMount(); - this._init.then(() => { - const { dispatch } = this.state.store; - const { - callerAvatarURL: avatarUrl, - callerName: name, - hasVideo - } = this.props; + const { dispatch } = this.state.store; + const { + callerAvatarURL: avatarUrl, + callerName: name, + hasVideo + } = this.props; - dispatch(incomingCallReceived({ - avatarUrl, - hasVideo, - name - })); + dispatch(incomingCallReceived({ + avatarUrl, + hasVideo, + name + })); - super._navigate({ component: IncomingCallPage }); - }); + super._navigate({ component: IncomingCallPage }); } } diff --git a/react/features/prejoin/components/PrejoinApp.js b/react/features/prejoin/components/PrejoinApp.js index f6b676bd0f..612992e963 100644 --- a/react/features/prejoin/components/PrejoinApp.js +++ b/react/features/prejoin/components/PrejoinApp.js @@ -36,39 +36,37 @@ export default class PrejoinApp extends BaseApp { * * @returns {void} */ - componentDidMount() { - super.componentDidMount(); + async componentDidMount() { + await super.componentDidMount(); - this._init.then(async () => { - const { store } = this.state; - const { dispatch } = store; - const { styleType } = this.props; + const { store } = this.state; + const { dispatch } = store; + const { styleType } = this.props; - super._navigate({ - component: PrejoinThirdParty, - props: { - className: styleType - } - }); + super._navigate({ + component: PrejoinThirdParty, + props: { + className: styleType + } + }); - const { startWithAudioMuted, startWithVideoMuted } = store.getState()['features/base/settings']; + const { startWithAudioMuted, startWithVideoMuted } = store.getState()['features/base/settings']; - dispatch(setConfig({ - prejoinConfig: { - enabled: true - }, - startWithAudioMuted, - startWithVideoMuted - })); + dispatch(setConfig({ + prejoinConfig: { + enabled: true + }, + startWithAudioMuted, + startWithVideoMuted + })); - const { tryCreateLocalTracks, errors } = createPrejoinTracks(); + const { tryCreateLocalTracks, errors } = createPrejoinTracks(); - const tracks = await tryCreateLocalTracks; + const tracks = await tryCreateLocalTracks; - batch(() => { - dispatch(initPrejoin(tracks, errors)); - dispatch(makePrecallTest(getConferenceOptions(store.getState()))); - }); + batch(() => { + dispatch(initPrejoin(tracks, errors)); + dispatch(makePrecallTest(getConferenceOptions(store.getState()))); }); }