Redux - Loading initial state asynchronously

Graham picture Graham · May 23, 2016 · Viewed 9.4k times · Source

I'm trying to work out the cleanest way to load the initial state of my Redux stores when it comes from API calls.

I understand that the typical way of providing the initial state is to generate it server-side on page load, and provide it to Redux createStore() as a simple object. However, I'm writing an app that I'm planning on packaging up in Electron and so this doesn't work.

The best that I've been able to come up with so far is to fire an action immediately after creating the store that will go and request the initial state for the store - either one action that retrieves the entire initial state or a number of actions that each retrieve the initial state for one part of the store. This would then mean that my code looks like:

const store = createStore(reducer, Immutable.Map(), middleware);
store.dispatch(loadStateForA());
store.dispatch(loadStateForB());
store.dispatch(loadStateForC());

Whilst this will work, it seems a bit on the crude side and so I'm wondering if there's some better alternative that I'm missing?

Answer

Gaurav Mantri picture Gaurav Mantri · Aug 4, 2016

I also encountered the same problem (also building an electron app). A part of my store has application settings which gets persisted on local file system and I needed to load it asynchronously on application's startup.

This is what I come up with. Being a "newbie" with React/Redux, I am very much interested in knowing the thoughts of the community on my approach and how it can be improved.

I created a method which loads the store asynchronously. This method returns a Promise which contains the store object.

export const configureStoreAsync = () => {
  return new Promise((resolve) => {
    const initialState = initialStoreState;//default initial store state
    try {
        //do some async stuff here to manipulate initial state...like read from local disk etc. 
        //This is again wrapped in its own Promises.
        const store = createStore(rootReducer, initialState, applyMiddleware(thunk));
        resolve(store);
      });
    } catch (error) {
      //To do .... log error!
      const store = createStore(rootReducer, initialState, applyMiddleware(thunk));
      console.log(store.getState());
      resolve(store);
    }
  });
};

Then in my application entry point, here's how I used it:

configureStoreAsync().then(result => {
  const store = result;
  return ReactDOM.render(
    <Provider store={store}>
      <App store={store}/>
    </Provider>,
    document.getElementById('Main'));
});

Like I said, this is my naive attempt at solving this problem and I am sure there must be better ways of handling this problem. I would be very much interested in knowing how this can be improved.