I was hoping to perform startup tasks using redux/saga, but if the AppLoading component is the first component loaded then that means the redux store won’t be available.
Wondering how others are doing this with redux, or if at all. Thanks.
I figured out a way of doing this so you can have all your startup tasks in a saga, and still use Expo’s <AppLoading> component. The tricky thing is having to subscribe to store updates manually, as <AppLoading> requires being the first and only component rendered.
// We want to display the native splash screen, until all the required assets have loaded.
// Expo has a component, <AppLoading>, for this.
// All the assets are loaded by the main saga. After they've loaded, the ASSETS_LOADED action
// is dispatched, updating the haveAssetsUpdated flag in the store.
// However, Expo requires that <AppLoading> is the first and only component loaded, therefore
// we can't switch between <AppLoading> and the rest of the App within <Provider>, as then
// <AppLoading> isn't the first or only component, so it won't work.
// Therefore we need another way of subscribing <App> to the store.
// We can do this by subscribing to a listener for store changes, using redux's store.subscribe().
// Inside the listener, if we detect that the haveAssetsLoaded flag has been set to true, then
// we mirror this in App's own state, so that the App component rerenders.
// As store.subscribe fires *every time* the store updates, we want to unsubscribe from this
// listener ASAP, i.e. as soon as haveAssetsLoaded has been set to true. This avoids the
// unnecessary performance hit of having the listener firing through the rest of the app's
// lifecycle.
class App extends Component {
state = {
haveAssetsLoaded: false,
};
constructor(props) {
super(props);
const unsubscribeFromStore = store.subscribe(() => {
if (store.getState().haveAssetsLoaded) {
// as soon as the main saga has loaded all assets, it sets haveAssetsLoaded: true in
// the store. We detect this here and, in turn, set haveAssetsLoaded: true in <App>'s
// state, causing App to rerender. Then unsubscribe this listener.
this.setState({ haveAssetsLoaded: true });
unsubscribeFromStore();
}
});
}
render() {
const { haveAssetsLoaded } = this.state;
if (!haveAssetsLoaded) {
return (
<AppLoading />
);
}
return (
<Provider store={store}>
<AppContainer />
</Provider>
);
}
}
Having a similar circumstance. In my case, I want to download some initial assets from the server (although I’m looking at assetBundlePatterns in app.json) and once those assets have downloaded using Expo.FileSystem I then also want to store the contents of this newly downloaded data into the Redux Store. I want to utilize the AppLoading directive so I had an idea where this data would be stored within a singleton until all of the Promises have completed and then using another React.Component to hydrate the state from this singleton. I haven’t tried this yet but I’ll be doing so later today…Feels wrong though but I can’t think of a better way to modularize this. Will report back.