Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

redux-observable - dispatch multiple redux actions in a single epic

I'm looking for way of dispatching multiple redux actions in a single Epic of redux-observable middleware.

Let's assume I have following Epic. Everytime when SEARCH event happens, Epic loads data from backend and dispatches RESULTS_LOADED action.

searchEpic = (action$) =>      action$     .ofType('SEARCH')     .mergeMap(         Observable         .fromPromise(searchPromise)         .map((data) => {             return {                 type: 'RESULTS_LOADED',                 results: data             }         })     ) 

Now, let's assume that I need dispatch additional action when the searchPromise is resolved.

The simplest way of doing so seems to have a second epic that will listen to RESULTS_LOADED and dispatch the second action. Like so:

resultsLoadedEpic = (action$) =>      action$     .ofType('RESULTS_LOADED')     .map(({results} => {          return {              type: 'MY_OTHER_ACTION',              results          }      }) 

In this simple example it's quite easy. But when Epics grow, I tend to find myself having a lot of redux actions which sole purpose is to trigger other actions. Additionally, some of the rxjs code needs to be repeated. I find this a bit ugly.

So, my question: Is there a way to dispatch multiple redux actions in a single Epic?

like image 344
dotintegral Avatar asked Nov 30 '16 11:11

dotintegral


1 Answers

There is no requirement that you make a one-to-one in/out ratio. So you can emit multiple actions using mergeMap (aka flatMap) if you need to:

const loaded = (results) => ({type: 'RESULTS_LOADED', results}); const otherAction = (results) => ({type: 'MY_OTHER_ACTION', results});  searchEpic = (action$) =>      action$     .ofType('SEARCH')     .mergeMap(         Observable         .fromPromise(searchPromise)         // Flattens this into two events on every search         .mergeMap((data) => Observable.of(           loaded(data),           otherAction(data))         ))     ) 

Note that any Rx operator that accepts an Observable also can accept a Promise, Array, or Iterable; consuming them as-if they were streams. So we could use an array instead for the same effect:

.mergeMap((data) => [loaded(data), otherAction(data)]) 

Which one you use depends on your personal style preferences and use case.

like image 169
paulpdaniels Avatar answered Oct 09 '22 02:10

paulpdaniels