瀏覽代碼

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 年之前
父節點
當前提交
e6ce5fd75f

+ 20
- 7
react/features/app/components/App.native.js 查看文件

@@ -28,11 +28,6 @@ declare var __DEV__;
28 28
  */
29 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 32
      * Identifier for this app on the native side.
38 33
      */
@@ -100,13 +95,31 @@ export class App extends AbstractApp {
100 95
      */
101 96
     async _extraInit() {
102 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 102
         const route = await _getRouteToRender();
104 103
 
105 104
         // We need the root navigator to be set early.
106 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 124
         // Check if serverURL is configured externally and not allowed to change.
112 125
         const serverURLChangeEnabled = getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true);

+ 22
- 0
react/features/app/reducer.native.js 查看文件

@@ -0,0 +1,22 @@
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 查看文件

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

+ 1
- 0
react/features/mobile/navigation/actionTypes.js 查看文件

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

+ 15
- 3
react/features/mobile/navigation/components/RootNavigationContainer.js 查看文件

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

Loading…
取消
儲存