Can I dispatch multiple actions from Redux action creators?

When using Redux, you may have come across a scenario where you’d like one action creator to dispatch multiple actions.

There are a few reasons you’d want to do this, but let’s consider the problem of handling a submit event from a form. In response, you’ll want to do multiple things. For example: RESET your form’s view model, POST your form’s data to the server, and also NAVIGATE to another route.

So should you dispatch separate actions for each of these behaviours, or instead dispatch a single action which is handled by each of the applicable reducers?


Actually, this is a trick question; with the appropriate store middleware, it is possible to do both at once!

How does this work? Well, no matter what you pass to dispatch, it is still a single action. Even if your action is an array of objects, or a function which can then create more action objects!

Dispatching functions which dispatch actions

But wait a moment. If we were to take the example of an action creator which returns a function for the redux-thunk middleware, aren’t we definitely calling dispatch multiple times?

function submit() {
  return function(dispatch) {
    dispatch({
      type: 'NAVIGATION/NAVIGATE',
      location: {name: 'documentEdit', {id: data.id}},
    )
    dispatch({
      type: 'DOCUMENT_VIEW/RESET',
      id: data.id,
    })
    dispatch({
      type: 'DOCUMENT_DATA/POST',
      data,
    })
  }
}

Indeed we are – but that doesn’t change the fact that what you originally dispatched is just a single function. All that is happening here is that redux-thunk then dispatches more actions as it processes your function.

Dispatching arrays

Things are a little more obvious if you use the redux-multi middleware to handle arrays of action objects:

function submit() {
  return [
    {
      type: 'NAVIGATION/NAVIGATE',
      location: {name: 'documentEdit', {id: data.id}},
    },
    {
      type: 'DOCUMENT_VIEW/RESET',
      id: data.id,
    },
    {
      type: 'DOCUMENT_DATA/POST',
      data,
    },
  ]
}

In this case, you’re clearly only dispatching one array object, even if the action objects it contains are then individually dispatched by the appropriate middleware.

Gotchas

The one thing to be careful of is that one call to store.dispatch may now result in many calls to your store’s subscribers:

JS Bin on jsbin.com

Sometimes this is what you actually want. But more likely, you only care about the last state from a given dispatch. In that case, batch up your listeners using the redux-batched-subscribe store enhancer:

import { createStore, applyMiddleware } from 'redux'
import reduxMulti from 'redux-multi'
import { batchedSubscribe } from 'redux-batched-subscribe'

// Add middleware to allow our action creators to return functions and arrays
const createStoreWithMiddleware = applyMiddleware(
  reduxThunk,
  reduxMulti,
)(createStore)

// Ensure our listeners are only called once, even when one of the above
// middleware call the underlying store's `dispatch` multiple times
const createStoreWithBatching = batchedSubscribe(
  fn => fn()
)(createStoreWithMiddleware)

const reducer = function(state = 0, action) { 
  return state + 1
}

// Create a store with our application reducer
const store = createStoreWithBatching(reducer)

store.subscribe(function() {
  console.log(store.getState())
})

store.dispatch([
  { type: 'FOO' },
  { type: 'BAR' },
])

// Output:
// 3

So it is OK to dispatch multiple actions from an action creator?

Yes! There is absolutely nothing wrong with doing so. Don’t worry, you’re fine.

But what if I want to dispatch actions in listeners?

Now you’re getting into let’s have a good think about this territory. Dispatching actions in listeners can cause fun problems like infinite loops and terrible performance.

But these problems aside, dispatching actions in listeners can still certainly be useful. For example, you might want to fetch data based on the route you arrive at, not the route that you think you will. So wouldn’t it be great if there was a safe way to do so?

And wouldn’t you believe it, there actually is! My solution is a pattern called actors, and there is a guide to it coming really soon. Make sure to join my newsletter, or you might miss out!

And to sweeten the deal, in return for your e-mail you’ll immediately receive three print-optimised PDF cheatsheets – for React (see preview), ES6 and JavaScript promises!

I will send you useful articles, cheatsheets and code.

I won't send you useless inbox filler. No spam, ever.
Unsubscribe at any time.

One more thing – I love hearing your opinions, questions, and offers of money. If you have something to say, send @james_k_nelson a tweet, or send me an e-mail at james@jamesknelson.com. Looking forward to hearing from you!

Read More

Related Projects

Share on Facebook0Tweet about this on TwitterShare on LinkedIn0Share on Reddit0

9 Comments Can I dispatch multiple actions from Redux action creators?

  1. ivan quintero

    Hello. I have been dispatching actions from other actions in an application and so far no problems. But after reading your article I am thinking that maybe I am doing an anti-pattern.

    This is more or less what I do in an action.

    ———————–
    export function(payload)
    {
    return function(dispatch)
    {
    return addRecordPromise.then(actionUpdateListRecords())
    }
    }
    ————————-

    What do you think?

    Reply
    1. James K Nelson

      Hi Ivan,

      Don’t worry – there is nothing anti-patternish about this. Dispatching actions from action creators is ok – after all, that is why they’re called action creators! It is dispatching actions after actions have been processed which is frowned upon. For example, in a Redux `subscribe` function.

      Reply
  2. Boris

    Hi James,

    I’ve just read your latest articles, and thanks for sharing all this stuff !

    About the topic of this post and the fact of dispatching multiples actions ending up to only one render (if I get it right), how would you handle the case of fetching some date and providing info about the loading status ?
    let’s say just displaying a spinner when the fetching starts and hiding it when it’s done…
    If you render just once, it doesn’t work.

    I’m using the promise middleware of redux which allows us to dispatch 3 actions when fetching data : REQUEST, SUCCESS, FAILURE.

    I modified these middleware so that it always returns a promise even if the action creator was not a promise.

    It allows me to do things like that in my component :

    buyVideoHandler (assetId, priceId) {
    const { dispatch, video } = this.props
    const payload = {
    priceId,
    productId : video._id,
    assetId
    }

    dispatch(buyVideo(payload)).then(() => {
    return dispatch(closeModal())
    }).then(() => {
    return dispatch(cleanCheckout())
    }).then(() => {
    this.context.history.pushState(null, `/${this.props.locale}/${ Routes.PATH.JOURNEY_VIEW }`)
    }).catch((err) => {
    debug(‘Error while buying video’, err)
    })
    }

    Here buyVideo make a call to an API endpoint, closeModal and cleanCheckout are just synchronous actions but which still return promises so that I can chain them.

    I prefer chaining the actions here (instead of inside the first action) because perhaps I don’t want to chain all these actions every time the buyVideo action will be called but only in this specific component.

    What do you think about that ?

    Thanks.
    Boris.

    Reply
    1. James K Nelson

      Hi Boris,

      I think I could probably make this a little clear in the article, but what the batching does is ensures that all of the actions dispatched from a single `dispatch` call in one tick result in only a single call to the handler function passed to subscribe.

      So in your example, most of the dispatched items will result in separate renders. Since closeModal and cleanCheckout are synchronous, they should be batched into a single render call. I believe this is the behaviour you expect?

      Reply
      1. Boris

        Hi James,

        sorry for this late reply.
        You’re right ! The expected behavior would be just one rendering after all the actions are done.

        I’ll try to use the redux-multi and redux-batched-subscribe middlewares for that !

        Thank you.

        Reply
  3. Max Hilland

    I’m trying to use the redux-multi method of dispatching an array of action creators, and it seems to work except for one small oddity – my redux-logger middleware is reporting that the encapsulating array is itself an action, which gets dispatched and logged as “undefined” before the actual action creators themselves get dispatched. is there a way to have it ignore the encapsulating array?

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *