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:
parent
1fcb8c8e44
commit
14df119373
|
@ -27,11 +27,6 @@ declare var __DEV__;
|
||||||
*/
|
*/
|
||||||
type Props = AbstractAppProps & {
|
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.
|
* Identifier for this app on the native side.
|
||||||
*/
|
*/
|
||||||
|
@ -98,13 +93,31 @@ export class App extends AbstractApp {
|
||||||
*/
|
*/
|
||||||
async _extraInit() {
|
async _extraInit() {
|
||||||
const { dispatch, getState } = this.state.store;
|
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();
|
const route = await _getRouteToRender();
|
||||||
|
|
||||||
// We need the root navigator to be set early.
|
// We need the root navigator to be set early.
|
||||||
await this._navigate(route);
|
await this._navigate(route);
|
||||||
|
|
||||||
// We set these early enough so then we avoid any unnecessary re-renders.
|
// HACK ALERT!
|
||||||
dispatch(updateFlags(this.props.flags));
|
// 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.
|
// 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);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
});
|
|
@ -8,4 +8,6 @@ import '../mobile/full-screen/reducer';
|
||||||
import '../mobile/watchos/reducer';
|
import '../mobile/watchos/reducer';
|
||||||
import '../shared-video/reducer';
|
import '../shared-video/reducer';
|
||||||
|
|
||||||
|
import './reducer.native';
|
||||||
|
|
||||||
import './reducers.any';
|
import './reducers.any';
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export const _ROOT_NAVIGATION_READY = '_ROOT_NAVIGATION_READY';
|
|
@ -2,11 +2,12 @@
|
||||||
|
|
||||||
import { NavigationContainer } from '@react-navigation/native';
|
import { NavigationContainer } from '@react-navigation/native';
|
||||||
import { createStackNavigator } from '@react-navigation/stack';
|
import { createStackNavigator } from '@react-navigation/stack';
|
||||||
import React from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux';
|
||||||
import { DialInSummary } from '../../../invite';
|
import { DialInSummary } from '../../../invite';
|
||||||
|
import { _ROOT_NAVIGATION_READY } from '../actionTypes';
|
||||||
import { rootNavigationRef } from '../rootNavigationContainerRef';
|
import { rootNavigationRef } from '../rootNavigationContainerRef';
|
||||||
import { screen } from '../routes';
|
import { screen } from '../routes';
|
||||||
import {
|
import {
|
||||||
|
@ -26,6 +27,11 @@ const RootStack = createStackNavigator();
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redux dispatch function.
|
||||||
|
*/
|
||||||
|
dispatch: Function,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is welcome page available?
|
* Is welcome page available?
|
||||||
*/
|
*/
|
||||||
|
@ -33,14 +39,21 @@ type Props = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const RootNavigationContainer = ({ isWelcomePageAvailable }: Props) => {
|
const RootNavigationContainer = ({ dispatch, isWelcomePageAvailable }: Props) => {
|
||||||
const initialRouteName = isWelcomePageAvailable
|
const initialRouteName = isWelcomePageAvailable
|
||||||
? screen.root : screen.connecting;
|
? screen.root : screen.connecting;
|
||||||
|
const onReady = useCallback(() => {
|
||||||
|
dispatch({
|
||||||
|
type: _ROOT_NAVIGATION_READY,
|
||||||
|
ready: true
|
||||||
|
});
|
||||||
|
}, [ dispatch ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaProvider>
|
<SafeAreaProvider>
|
||||||
<NavigationContainer
|
<NavigationContainer
|
||||||
independent = { true }
|
independent = { true }
|
||||||
|
onReady = { onReady }
|
||||||
ref = { rootNavigationRef }
|
ref = { rootNavigationRef }
|
||||||
theme = { navigationContainerTheme }>
|
theme = { navigationContainerTheme }>
|
||||||
<RootStack.Navigator
|
<RootStack.Navigator
|
||||||
|
@ -89,4 +102,3 @@ function mapStateToProps(state: Object) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps)(RootNavigationContainer);
|
export default connect(mapStateToProps)(RootNavigationContainer);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue