fix(rn,navigation) wait until the root navigator is initialized

There is a race condition in the root navigatior's initialization.

It's possible that it's initialized a touch too late and SDK users who
try to navigate to a conference end up stuck in the connecting screen
because the navigator is null.

This PR waits for it to be initilized by very unorthodox means, it's a
horrible hack which we need to undo, but for that we need to break
appart the inheritance relationship between App.{web,native},
AbstractApp and BaseApp because it's very inflexible.

The flags are now initialized very early so the naviggator sees if the
welcome page is enabled or not.
This commit is contained in:
Saúl Ibarra Corretgé 2022-05-06 11:20:22 +02:00
parent 1fcb8c8e44
commit 14df119373
5 changed files with 60 additions and 10 deletions

View File

@ -27,11 +27,6 @@ declare var __DEV__;
*/
type Props = AbstractAppProps & {
/**
* An object of colors that override the default colors of the app/sdk.
*/
colorScheme: ?Object,
/**
* Identifier for this app on the native side.
*/
@ -98,13 +93,31 @@ export class App extends AbstractApp {
*/
async _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));
const route = await _getRouteToRender();
// We need the root navigator to be set early.
await this._navigate(route);
// We set these early enough so then we avoid any unnecessary re-renders.
dispatch(updateFlags(this.props.flags));
// HACK ALERT!
// Wait until the root navigator is ready.
// We really need to break the inheritance relationship between App,
// AbstractApp and BaseApp, it's very inflexible and cumbersome right now.
const rootNavigationReady = new Promise(resolve => {
const i = setInterval(() => {
const { ready } = getState()['features/app'] || {};
if (ready) {
clearInterval(i);
resolve();
}
}, 50);
});
await rootNavigationReady;
// Check if serverURL is configured externally and not allowed to change.
const serverURLChangeEnabled = getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true);

View File

@ -0,0 +1,22 @@
import { ReducerRegistry } from '../base/redux';
import { _ROOT_NAVIGATION_READY } from '../mobile/navigation/actionTypes';
/**
* Listen for actions which changes the state of the app feature.
*
* @param {Object} state - The Redux state of the feature features/app.
* @param {Object} action - Action object.
* @param {string} action.type - Type of action.
* @returns {Object}
*/
ReducerRegistry.register('features/app', (state = {}, action) => {
switch (action.type) {
case _ROOT_NAVIGATION_READY:
return {
...state,
ready: action.ready
};
default:
return state;
}
});

View File

@ -8,4 +8,6 @@ import '../mobile/full-screen/reducer';
import '../mobile/watchos/reducer';
import '../shared-video/reducer';
import './reducer.native';
import './reducers.any';

View File

@ -0,0 +1 @@
export const _ROOT_NAVIGATION_READY = '_ROOT_NAVIGATION_READY';

View File

@ -2,11 +2,12 @@
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import React from 'react';
import React, { useCallback } from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { connect } from '../../../base/redux';
import { DialInSummary } from '../../../invite';
import { _ROOT_NAVIGATION_READY } from '../actionTypes';
import { rootNavigationRef } from '../rootNavigationContainerRef';
import { screen } from '../routes';
import {
@ -26,6 +27,11 @@ const RootStack = createStackNavigator();
type Props = {
/**
* Redux dispatch function.
*/
dispatch: Function,
/**
* Is welcome page available?
*/
@ -33,14 +39,21 @@ type Props = {
}
const RootNavigationContainer = ({ isWelcomePageAvailable }: Props) => {
const RootNavigationContainer = ({ dispatch, isWelcomePageAvailable }: Props) => {
const initialRouteName = isWelcomePageAvailable
? screen.root : screen.connecting;
const onReady = useCallback(() => {
dispatch({
type: _ROOT_NAVIGATION_READY,
ready: true
});
}, [ dispatch ]);
return (
<SafeAreaProvider>
<NavigationContainer
independent = { true }
onReady = { onReady }
ref = { rootNavigationRef }
theme = { navigationContainerTheme }>
<RootStack.Navigator
@ -89,4 +102,3 @@ function mapStateToProps(state: Object) {
}
export default connect(mapStateToProps)(RootNavigationContainer);