fix(rn, web) await initialisation before dispatching appWillMount

This commit is contained in:
tmoldovan8x8 2022-01-07 15:18:24 +02:00 committed by GitHub
parent 8de024a699
commit 307e253276
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 114 additions and 95 deletions

View File

@ -38,14 +38,12 @@ export class AbstractApp extends BaseApp<Props, *> {
* *
* @inheritdoc * @inheritdoc
*/ */
componentDidMount() { async componentDidMount() {
super.componentDidMount(); await super.componentDidMount();
this._init.then(() => { // If a URL was explicitly specified to this React Component, then
// If a URL was explicitly specified to this React Component, 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());
});
} }
/** /**
@ -53,23 +51,23 @@ export class AbstractApp extends BaseApp<Props, *> {
* *
* @inheritdoc * @inheritdoc
*/ */
componentDidUpdate(prevProps: Props) { async componentDidUpdate(prevProps: Props) {
const previousUrl = toURLString(prevProps.url); const previousUrl = toURLString(prevProps.url);
const currentUrl = toURLString(this.props.url); const currentUrl = toURLString(this.props.url);
const previousTimestamp = prevProps.timestamp; const previousTimestamp = prevProps.timestamp;
const currentTimestamp = this.props.timestamp; const currentTimestamp = this.props.timestamp;
this._init.then(() => { await this._init;
// Deal with URL changes.
if (previousUrl !== currentUrl // Deal with URL changes.
// XXX Refer to the implementation of loadURLObject: in if (previousUrl !== currentUrl
// ios/sdk/src/JitsiMeetView.m for further information.
|| previousTimestamp !== currentTimestamp) { // XXX Refer to the implementation of loadURLObject: in
this._openURL(currentUrl || this._getDefaultURL()); // ios/sdk/src/JitsiMeetView.m for further information.
} || previousTimestamp !== currentTimestamp) {
}); this._openURL(currentUrl || this._getDefaultURL());
}
} }
/** /**

View File

@ -81,40 +81,45 @@ export class App extends AbstractApp {
* *
* @returns {void} * @returns {void}
*/ */
componentDidMount() { async componentDidMount() {
super.componentDidMount(); await super.componentDidMount();
SplashScreen.hide(); 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. // We set these early enough so then we avoid any unnecessary re-renders.
dispatch(updateFlags(this.props.flags)); dispatch(updateFlags(this.props.flags));
// Check if serverURL is configured externally and not allowed to change. // Check if serverURL is configured externally and not allowed to change.
const serverURLChangeEnabled = getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true); const serverURLChangeEnabled = getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true);
if (!serverURLChangeEnabled) { if (!serverURLChangeEnabled) {
// As serverURL is provided externally, so we push it to settings. // As serverURL is provided externally, so we push it to settings.
if (typeof this.props.url !== 'undefined') { if (typeof this.props.url !== 'undefined') {
const { serverURL } = this.props.url; const { serverURL } = this.props.url;
if (typeof serverURL !== 'undefined') { if (typeof serverURL !== 'undefined') {
dispatch(updateSettings({ serverURL })); dispatch(updateSettings({ serverURL }));
}
} }
} }
}
dispatch(updateSettings(this.props.userInfo || {})); dispatch(updateSettings(this.props.userInfo || {}));
// Update settings with feature-flag. // Update settings with feature-flag.
const callIntegrationEnabled = this.props.flags[CALL_INTEGRATION_ENABLED]; const callIntegrationEnabled = this.props.flags[CALL_INTEGRATION_ENABLED];
if (typeof callIntegrationEnabled !== 'undefined') { if (typeof callIntegrationEnabled !== 'undefined') {
dispatch(updateSettings({ disableCallIntegration: !callIntegrationEnabled })); dispatch(updateSettings({ disableCallIntegration: !callIntegrationEnabled }));
} }
});
} }
/** /**

View File

@ -16,6 +16,7 @@ import {
StateListenerRegistry StateListenerRegistry
} from '../../redux'; } from '../../redux';
import { SoundCollection } from '../../sounds'; import { SoundCollection } from '../../sounds';
import { createDeferred } from '../../util';
import { appWillMount, appWillUnmount } from '../actions'; import { appWillMount, appWillUnmount } from '../actions';
import logger from '../logger'; import logger from '../logger';
@ -43,7 +44,10 @@ type State = {
* @abstract * @abstract
*/ */
export default class BaseApp extends Component<*, State> { 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. * Initializes a new {@code BaseApp} instance.
@ -64,8 +68,8 @@ export default class BaseApp extends Component<*, State> {
* Initializes the app. * Initializes the app.
* *
* @inheritdoc * @inheritdoc
*/ */
componentDidMount() { async componentDidMount() {
/** /**
* Make the mobile {@code BaseApp} wait until the {@code AsyncStorage} * Make the mobile {@code BaseApp} wait until the {@code AsyncStorage}
* implementation of {@code Storage} initializes fully. * implementation of {@code Storage} initializes fully.
@ -74,21 +78,28 @@ export default class BaseApp extends Component<*, State> {
* @see {@link #_initStorage} * @see {@link #_initStorage}
* @type {Promise} * @type {Promise}
*/ */
this._init = this._initStorage() this._init = createDeferred();
.catch(err => {
/* BaseApp should always initialize! */ try {
logger.error(err); await this._initStorage();
})
.then(() => new Promise(resolve => { const setStatePromise = new Promise(resolve => {
this.setState({ this.setState({
store: this._createStore() store: this._createStore()
}, resolve); }, 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(); return _initializing || Promise.resolve();
} }
/**
* Extra initialisation that subclasses might require.
*
* @returns {void}
*/
_extraInit() {
// To be implemented by subclass.
}
/** /**
* Implements React's {@link Component#render()}. * Implements React's {@link Component#render()}.
* *

View File

@ -43,24 +43,22 @@ export default class IncomingCallApp extends BaseApp<Props> {
* *
* @returns {void} * @returns {void}
*/ */
componentDidMount() { async componentDidMount() {
super.componentDidMount(); await super.componentDidMount();
this._init.then(() => { const { dispatch } = this.state.store;
const { dispatch } = this.state.store; const {
const { callerAvatarURL: avatarUrl,
callerAvatarURL: avatarUrl, callerName: name,
callerName: name, hasVideo
hasVideo } = this.props;
} = this.props;
dispatch(incomingCallReceived({ dispatch(incomingCallReceived({
avatarUrl, avatarUrl,
hasVideo, hasVideo,
name name
})); }));
super._navigate({ component: IncomingCallPage }); super._navigate({ component: IncomingCallPage });
});
} }
} }

View File

@ -36,39 +36,37 @@ export default class PrejoinApp extends BaseApp<Props> {
* *
* @returns {void} * @returns {void}
*/ */
componentDidMount() { async componentDidMount() {
super.componentDidMount(); await super.componentDidMount();
this._init.then(async () => { const { store } = this.state;
const { store } = this.state; const { dispatch } = store;
const { dispatch } = store; const { styleType } = this.props;
const { styleType } = this.props;
super._navigate({ super._navigate({
component: PrejoinThirdParty, component: PrejoinThirdParty,
props: { props: {
className: styleType className: styleType
} }
}); });
const { startWithAudioMuted, startWithVideoMuted } = store.getState()['features/base/settings']; const { startWithAudioMuted, startWithVideoMuted } = store.getState()['features/base/settings'];
dispatch(setConfig({ dispatch(setConfig({
prejoinConfig: { prejoinConfig: {
enabled: true enabled: true
}, },
startWithAudioMuted, startWithAudioMuted,
startWithVideoMuted startWithVideoMuted
})); }));
const { tryCreateLocalTracks, errors } = createPrejoinTracks(); const { tryCreateLocalTracks, errors } = createPrejoinTracks();
const tracks = await tryCreateLocalTracks; const tracks = await tryCreateLocalTracks;
batch(() => { batch(() => {
dispatch(initPrejoin(tracks, errors)); dispatch(initPrejoin(tracks, errors));
dispatch(makePrecallTest(getConferenceOptions(store.getState()))); dispatch(makePrecallTest(getConferenceOptions(store.getState())));
});
}); });
} }