Browse Source

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.
master
Saúl Ibarra Corretgé 3 years ago
parent
commit
e6ce5fd75f

+ 20
- 7
react/features/app/components/App.native.js View File

28
  */
28
  */
29
 type Props = AbstractAppProps & {
29
 type Props = AbstractAppProps & {
30
 
30
 
31
-    /**
32
-     * An object of colors that override the default colors of the app/sdk.
33
-     */
34
-    colorScheme: ?Object,
35
-
36
     /**
31
     /**
37
      * Identifier for this app on the native side.
32
      * Identifier for this app on the native side.
38
      */
33
      */
100
      */
95
      */
101
     async _extraInit() {
96
     async _extraInit() {
102
         const { dispatch, getState } = this.state.store;
97
         const { dispatch, getState } = this.state.store;
98
+
99
+        // We set these early enough so then we avoid any unnecessary re-renders.
100
+        dispatch(updateFlags(this.props.flags));
101
+
103
         const route = await _getRouteToRender();
102
         const route = await _getRouteToRender();
104
 
103
 
105
         // We need the root navigator to be set early.
104
         // We need the root navigator to be set early.
106
         await this._navigate(route);
105
         await this._navigate(route);
107
 
106
 
108
-        // We set these early enough so then we avoid any unnecessary re-renders.
109
-        dispatch(updateFlags(this.props.flags));
107
+        // HACK ALERT!
108
+        // Wait until the root navigator is ready.
109
+        // We really need to break the inheritance relationship between App,
110
+        // AbstractApp and BaseApp, it's very inflexible and cumbersome right now.
111
+        const rootNavigationReady = new Promise(resolve => {
112
+            const i = setInterval(() => {
113
+                const { ready } = getState()['features/app'] || {};
114
+
115
+                if (ready) {
116
+                    clearInterval(i);
117
+                    resolve();
118
+                }
119
+            }, 50);
120
+        });
121
+
122
+        await rootNavigationReady;
110
 
123
 
111
         // Check if serverURL is configured externally and not allowed to change.
124
         // Check if serverURL is configured externally and not allowed to change.
112
         const serverURLChangeEnabled = getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true);
125
         const serverURLChangeEnabled = getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true);

+ 22
- 0
react/features/app/reducer.native.js View File

1
+import { ReducerRegistry } from '../base/redux';
2
+import { _ROOT_NAVIGATION_READY } from '../mobile/navigation/actionTypes';
3
+
4
+/**
5
+ * Listen for actions which changes the state of the app feature.
6
+ *
7
+ * @param {Object} state - The Redux state of the feature features/app.
8
+ * @param {Object} action - Action object.
9
+ * @param {string} action.type - Type of action.
10
+ * @returns {Object}
11
+ */
12
+ReducerRegistry.register('features/app', (state = {}, action) => {
13
+    switch (action.type) {
14
+    case _ROOT_NAVIGATION_READY:
15
+        return {
16
+            ...state,
17
+            ready: action.ready
18
+        };
19
+    default:
20
+        return state;
21
+    }
22
+});

+ 2
- 0
react/features/app/reducers.native.js View File

8
 import '../mobile/watchos/reducer';
8
 import '../mobile/watchos/reducer';
9
 import '../shared-video/reducer';
9
 import '../shared-video/reducer';
10
 
10
 
11
+import './reducer.native';
12
+
11
 import './reducers.any';
13
 import './reducers.any';

+ 1
- 0
react/features/mobile/navigation/actionTypes.js View File

1
+export const _ROOT_NAVIGATION_READY = '_ROOT_NAVIGATION_READY';

+ 15
- 3
react/features/mobile/navigation/components/RootNavigationContainer.js View File

1
 import { NavigationContainer } from '@react-navigation/native';
1
 import { NavigationContainer } from '@react-navigation/native';
2
 import { createStackNavigator } from '@react-navigation/stack';
2
 import { createStackNavigator } from '@react-navigation/stack';
3
-import React from 'react';
3
+import React, { useCallback } from 'react';
4
 
4
 
5
 import { connect } from '../../../base/redux';
5
 import { connect } from '../../../base/redux';
6
 import { DialInSummary } from '../../../invite';
6
 import { DialInSummary } from '../../../invite';
7
+import { _ROOT_NAVIGATION_READY } from '../actionTypes';
7
 import { rootNavigationRef } from '../rootNavigationContainerRef';
8
 import { rootNavigationRef } from '../rootNavigationContainerRef';
8
 import { screen } from '../routes';
9
 import { screen } from '../routes';
9
 import {
10
 import {
23
 
24
 
24
 type Props = {
25
 type Props = {
25
 
26
 
27
+    /**
28
+     * Redux dispatch function.
29
+     */
30
+    dispatch: Function,
31
+
26
     /**
32
     /**
27
     * Is welcome page available?
33
     * Is welcome page available?
28
     */
34
     */
30
 }
36
 }
31
 
37
 
32
 
38
 
33
-const RootNavigationContainer = ({ isWelcomePageAvailable }: Props) => {
39
+const RootNavigationContainer = ({ dispatch, isWelcomePageAvailable }: Props) => {
34
     const initialRouteName = isWelcomePageAvailable
40
     const initialRouteName = isWelcomePageAvailable
35
         ? screen.root : screen.connecting;
41
         ? screen.root : screen.connecting;
42
+    const onReady = useCallback(() => {
43
+        dispatch({
44
+            type: _ROOT_NAVIGATION_READY,
45
+            ready: true
46
+        });
47
+    }, [ dispatch ]);
36
 
48
 
37
     return (
49
     return (
38
         <NavigationContainer
50
         <NavigationContainer
39
             independent = { true }
51
             independent = { true }
52
+            onReady = { onReady }
40
             ref = { rootNavigationRef }
53
             ref = { rootNavigationRef }
41
             theme = { navigationContainerTheme }>
54
             theme = { navigationContainerTheme }>
42
             <RootStack.Navigator
55
             <RootStack.Navigator
86
 }
99
 }
87
 
100
 
88
 export default connect(mapStateToProps)(RootNavigationContainer);
101
 export default connect(mapStateToProps)(RootNavigationContainer);
89
-

Loading…
Cancel
Save