diff --git a/keyserver/src/responders/website-responders.js b/keyserver/src/responders/website-responders.js
--- a/keyserver/src/responders/website-responders.js
+++ b/keyserver/src/responders/website-responders.js
@@ -237,6 +237,7 @@
commServicesAccessToken: t.Nil,
inviteLinksStore: inviteLinksStoreValidator,
keyserverStore: keyserverStoreValidator,
+ initialStateLoaded: tBool(false),
});
async function websiteResponder(
@@ -603,6 +604,7 @@
commServicesAccessToken: null,
inviteLinksStore: inviteLinksStorePromise,
keyserverStore: keyserverStorePromise,
+ initialStateLoaded: false,
});
const validatedInitialReduxState = validateOutput(
viewer.platformDetails,
diff --git a/web/redux/initial-state-gate.js b/web/redux/initial-state-gate.js
new file mode 100644
--- /dev/null
+++ b/web/redux/initial-state-gate.js
@@ -0,0 +1,68 @@
+// @flow
+
+import * as React from 'react';
+import { useDispatch } from 'react-redux';
+import { PersistGate } from 'redux-persist/es/integration/react.js';
+import type { Persistor } from 'redux-persist/es/types';
+
+import { useServerCall } from 'lib/utils/action-utils.js';
+import { infoFromURL } from 'lib/utils/url-utils.js';
+
+import { getInitialReduxState, setInitialReduxState } from './action-types.js';
+import { useSelector } from './redux-utils.js';
+import Loading from '../loading.react.js';
+
+type Props = {
+ +persistor: Persistor,
+ +children: React.Node,
+};
+function InitialReduxStateGate(props: Props): React.Node {
+ const { children, persistor } = props;
+ const callGetInitialReduxState = useServerCall(getInitialReduxState);
+ const dispatch = useDispatch();
+
+ const [initError, setInitError] = React.useState(null);
+ React.useEffect(() => {
+ if (initError) {
+ throw initError;
+ }
+ });
+
+ const isRehydrated = useSelector(
+ state => state._persist?.rehydrated ?? false,
+ );
+ const prevIsRehydrated = React.useRef(false);
+ React.useEffect(() => {
+ if (!prevIsRehydrated.current && isRehydrated) {
+ prevIsRehydrated.current = isRehydrated;
+ (async () => {
+ try {
+ const urlInfo = infoFromURL(decodeURI(window.location.href));
+ const payload = await callGetInitialReduxState(urlInfo);
+ dispatch({ type: setInitialReduxState, payload });
+ } catch (err) {
+ setInitError(err);
+ }
+ })();
+ }
+ }, [callGetInitialReduxState, dispatch, isRehydrated]);
+
+ const initialStateLoaded = useSelector(state => state.initialStateLoaded);
+
+ const childFunction = React.useCallback(
+ // This argument is passed from `PersistGate`. It means that the state is
+ // rehydrated and we can start fetching the initial info.
+ bootstrapped => {
+ if (bootstrapped && initialStateLoaded) {
+ return children;
+ } else {
+ return ;
+ }
+ },
+ [children, initialStateLoaded],
+ );
+
+ return {childFunction};
+}
+
+export default InitialReduxStateGate;
diff --git a/web/redux/redux-setup.js b/web/redux/redux-setup.js
--- a/web/redux/redux-setup.js
+++ b/web/redux/redux-setup.js
@@ -97,6 +97,7 @@
+commServicesAccessToken: ?string,
+inviteLinksStore: InviteLinksStore,
+keyserverStore: KeyserverStore,
+ +initialStateLoaded: boolean,
};
export type Action =
@@ -140,6 +141,7 @@
},
},
},
+ initialStateLoaded: true,
});
} else if (action.type === updateWindowDimensionsActionType) {
return validateState(oldState, {
diff --git a/web/root.js b/web/root.js
--- a/web/root.js
+++ b/web/root.js
@@ -7,7 +7,6 @@
import { createStore, applyMiddleware, type Store } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProduction.js';
import { persistReducer, persistStore } from 'redux-persist';
-import { PersistGate } from 'redux-persist/es/integration/react.js';
import thunk from 'redux-thunk';
import { reduxLoggerMiddleware } from 'lib/utils/action-logger.js';
@@ -16,7 +15,7 @@
import { SQLiteDataHandler } from './database/sqlite-data-handler.js';
import { localforageConfig } from './database/utils/constants.js';
import ErrorBoundary from './error-boundary.react.js';
-import Loading from './loading.react.js';
+import InitialReduxStateGate from './redux/initial-state-gate.js';
import { persistConfig } from './redux/persist.js';
import { type AppState, type Action, reducer } from './redux/redux-setup.js';
import history from './router-history.js';
@@ -36,15 +35,15 @@
const RootProvider = (): React.Node => (
- }>
-
+
+
-
-
+
+
);