0

My application allows users to enter data in many different places, and each time I use something like this to call an async thunk:

dispatch(handleDataEntry({ key, value })

In some cases the results of the API call inform the application that another datapoint needs to be set client-side, so the downstream extraReducer in my slice (using createSlice from @reduxjs/toolkit) should now re-dispatch the thunk. But this seems to be an anti-pattern, and in any case I couldn't find a way to do this, so I'm storing sideEffectKey and sideEffectValue in state and having components in cases of non-nullity dispatch the thunk themselves.

This doesn't seem like a good solution, and in fact since sideEffectKey and sideEffectValue stay non-null until the second API call completes and I can clear them, handleDataEntry gets dispatched multiple times, causing me problems.

What's a better solution? Is there some way to do something like this?

[handleDataEntry.fulfilled.toString()]: (
            state: Store,
            action: {
                payload: {
                    sideEffectKey: string | null
                    sideEffectValue: string | null
                }
            }
) => {
  if (action.payload.sideEffectKey) { 
     dispatch(handleDataEntry({ key: sideEffectKey, value: sideEffectValue }))
  }
}
Julien Kode
  • 5,010
  • 21
  • 36
ed94133
  • 1,477
  • 2
  • 19
  • 40

1 Answers1

1

How to dispatch a thunk when another one is finished ?

How to listen to a thunk status ?

In your case when you thunk is finish and succeed you dispatch fulfilled event.

Because create async thunk create actions for theses 3 different states:

  • pending
  • fulfilled
  • rejected

By default your thunk cannot listen theses actions dispatched by your other thunk. You need a listener middleware to do it

Listener middleware

With listener middleware you can listen to any actions to execute some logic.

You have three different way to listen:

  • one with an actionCreator
  • one with a matcher
  • one with a predicate

How to use listener middleware ?

In your case you can add a matcher on this to execute handleDataEntry when it has finished.

listenerMiddleware.startListening({
  matcher: handleDataEntry.fulfilled,
  effect: async (action, listenerApi) => {
     if (action.payload.sideEffectKey) { 
        listenerApi.dispatch(handleDataEntry({ key: sideEffectKey, value: sideEffectValue }))
     }
    }
  },
})

Final note

Just be careful on your case you thunk your thunk to call it itself maybe ad a limit. To make sure to do not have an infinite fetch calls

Avoiding side effect in reducers

You are right reducers must be pure and should not have side effects.

Julien Kode
  • 5,010
  • 21
  • 36