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
*/
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<Props, *> {
*
* @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());
}
}
/**

View File

@ -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 }));
}
}
/**

View File

@ -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()}.
*

View File

@ -43,24 +43,22 @@ export default class IncomingCallApp extends BaseApp<Props> {
*
* @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 });
}
}

View File

@ -36,39 +36,37 @@ export default class PrejoinApp extends BaseApp<Props> {
*
* @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())));
});
}