Redux: Sequential actions?

Created on 12 Aug 2015  路  11Comments  路  Source: reduxjs/redux

I'm trying to figure out how to do sequential actions on startup. In my case this sort of looks like this in pseudo-code:

App.start()
  .then(getSetup)
  .then(fetchLocales)
  .then(fetchOffers)

We need getSetup action to finish before calling fetchLocales, as the setup store contains info we need for fetching the locales data... Any guidance here?

question

Most helpful comment

@StevenLangbroek how about something like this:

import { getSetup, fetchTranslations, fetchOffers} from './utils/api';

const actioncreator = {
  bootstrap() {
    return (dispatch, getState) => {
      getSetup()
        .then(setup => dispatch({
            type: FETCH_SETUP,
            payload: setup
        }))
        .then(() => {
          // since `dispatch` is synchronous a call to `getState` will yield you the current state
          const subNode = getState().something.subNode;
          return fetchTranslations(subNode);
        })
        .then(translations => dispatch({
            type: FETCH_TRANSLATIONS,
            payload: translations
          }))
        .then(fetchOffers)
        .then(offers => dispatch({
          type: FETCH_OFFERS,
          payload: offers
        }));
    }
  }
}

It's not tested but you get the idea.

All 11 comments

After store creation you can do store.dispatch(somePropmiseChain) you need redux-promise middleware as well I suppose to use promises as action creators.

@StevenLangbroek You could use the thunk middleware to create a bootstrap action creator, which contains your full promise chain and dispatches actions on the go.

Sorry I should've been a bit more clear maybe. The chain looks more like this:

getSetup().
  then(setup => 
    // How do I ensure this has been reduced into the store...
    dispatch({
      type: FETCH_SETUP,
      payload: setup
    })
  )
  // ...before running this action? fetchTranslations needs
  // a subnode of the `setup` store...
  .then(fetchTranslations)
  .then(translations =>     
    dispatch({
      type: FETCH_TRANSLATIONS,
      payload: translations
    })
  )
  .then(fetchOffers)
  .then(offers => dispatch({
    type: FETCH_OFFERS,
    payload: offers
  }));

@StevenLangbroek how about something like this:

import { getSetup, fetchTranslations, fetchOffers} from './utils/api';

const actioncreator = {
  bootstrap() {
    return (dispatch, getState) => {
      getSetup()
        .then(setup => dispatch({
            type: FETCH_SETUP,
            payload: setup
        }))
        .then(() => {
          // since `dispatch` is synchronous a call to `getState` will yield you the current state
          const subNode = getState().something.subNode;
          return fetchTranslations(subNode);
        })
        .then(translations => dispatch({
            type: FETCH_TRANSLATIONS,
            payload: translations
          }))
        .then(fetchOffers)
        .then(offers => dispatch({
          type: FETCH_OFFERS,
          payload: offers
        }));
    }
  }
}

It's not tested but you get the idea.

Right, ok, that makes sense. I've been toying with this, but the next problem is that the fetchOffers action is also a stand-alone action, so it's curried, and should receive dispatch, getState in the 2nd function...

@StevenLangbroek If it doesn't fit the dispatch format, you can always just write a wrapper to do it for you. It's not optimal, but that's how most people do it. Or convince management/upstream to change it (less likely to be successful).

You can use redux-combine-actions for sequential actions.
It will look something like this:

export function fetchData() {

    return {
        types: [
            'COMBINED_ACTION_START',
            'COMBINED ACTION_SUCCESS',
            'COMBINED ACTION_ERROR'
        ],

        // Set true for sequential actions
        sequence: true,

        // Pass actions in array
        payload: [getSetup, fetchTranslations, fetchOffers]
    };
}

This will dispatch actions in the following sequence:
_COMBINED_ACTION_START_ -> _FETCH_SETUP_ -> _FETCH_TRANSLATIONS_ -> _FETCH_OFFERS_ -> _COMBINED_ACTION_SUCCESS_

@itsmepetrov your middleware looks interesting. Could you update the readme explaining how to apply it , how does the types array work, etc.?
Thanks!

@nickdima I've updated documentation for the middleware and I hope docs will answer your questions. But I'm always glad to help.

@itsmepetrov much better! Thanks!

Closing, as seems resolved by either redux-combine-actions or manual action creator composition with redux-thunk.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vraa picture vraa  路  3Comments

mickeyreiss-visor picture mickeyreiss-visor  路  3Comments

timdorr picture timdorr  路  3Comments

parallelthought picture parallelthought  路  3Comments

amorphius picture amorphius  路  3Comments