armasm
armasm

Reputation: 23

Is it valid to dispatch multiple times inside redux middleware?

I'm trying to wrap my head around Redux or state management in general for the front-end applications.

As far as I know, there are three basic libraries to create complex actions logic: redux-thunk, redux-saga and redux-observable.

I'm using redux-thunk to create a chain of the async operations, but I found them a little bit inappropriate: action creators should create actions, not functions.

In order to get around this, I've created actions (simple action creators) and operations (thunks) with redux-toolkit, but I still see them a little bit confusing:

export function add(state, action) { ... }
export function added(state, action) { ... }
export function addItem(payload) {
  return async (dispatch) => {
    dispatch(actions.add(payload))

    const { data } = await Items.create(action.payload); 

    dispatch(actions.added(payload))
  }
}

It looks ok, but I can see myself trying to dispatch add directly in the future.


Using redux-saga seems unnatural thanks to the generator syntax. I don't have to say anything about redux-observable, it's over-complicated for this simple task.

So I tried to use simple custom middleware for this kind of work, but I don't really know if it's a "good practice" or "bad practice". However, it allows to use simple actions to fire an observer that dispatches matching function:

let listeners = {}

export const observer = store => next => action => {
  const result = next(action)

  if (action.type in listeners) {
    listeners[action.type](store.dispatch, action)
  }

  return result
}

export const createListener = (action, listener) => {
  listeners[action.type] = listener
}

Code above allows to write "observers" / "listeners" like below:

createListener(actions.add, async (dispatch, action) => {
  const { data } = await Items.create(action.payload)

  dispatch(actions.added(data))
})

...which allows to dispatch callback attached to the listened actions. Looks very simple and clean for me.

Is this a bad way to solve this problem?

Upvotes: 1

Views: 905

Answers (1)

markerikson
markerikson

Reputation: 67499

I'm a Redux maintainer and creator of Redux Toolkit.

Thunks exist to allow you to move complex synchronous and semi-complex async logic outside of components. Components typically use action creators to avoid knowing the details of how to define a given action object. Thunk action creators exist to provide parallel syntax, allowing components to kick off logic without needing to know the details of whether it's a simple action dispatch or something more complex.

That said, thunks do not give you a way to respond to dispatched actions, because the only thing the thunk middleware does is look to see if you've passed a thunk function to dispatch, and if so, call it. Sagas and observables both provide APIs that let you run additional logic in response to dispatched actions. See the Redux FAQ entry on "how do I choose between thunks, sagas, and observables?" for more details.

The middleware you've just shown there is a typical example of a simple "action listener" middleware - really a much simpler version of what sagas and observables let you do. In fact, we're hoping to add a similar middleware to Redux Toolkit, but haven't done so yet.

So, yes, the middleware itself is a valid tool to create, but you haven't provided sufficient information on what specific problem you're trying to solve, so I can't say whether it's an appropriate tool for your problem.

Upvotes: 3

Related Questions