Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to perform side-effect inside of an epic in redux-observable?

In redux-observable, epics are accepting stream of actions and returning back new stream of actions. In my use-case I need to send analytics event after some action was dispatched and do nothing after.

With redux-saga, I can just listen that action using takeEvery, and perform a side-effect inside of a saga function:

function* saga() {
  yield takeEvery('SOME_ACTION', function*() {
    sendAnalytics();
  })
}

But how can I achieve the same with redux-observable? There is pretty much side effects, that are not requiring dispatching new actions, like initializing plugins, logging, setting cookies etc...

If it's an anti-pattern for both of these libraries, what solution should be used for these kinds of effects?

like image 967
1ven Avatar asked Aug 09 '17 10:08

1ven


1 Answers

Definitely not an anti-pattern outright to have an epic which is "read-only"--but I want to caution that it's often a sign a person is doing something less-than-idiomatic, but this is not one of those cases.

There are likely many ways of accomplishing this in Rx. Here are two:

do + ignoreElements

I think this is the most clear of what it does. do is only ever used to perform a side effect (often logging) for next/error/complete without affecting the stream. We then use ignoreElements to prevent the SOME_ACTION from being dispatched again (which would cause infinite recursion). See the rxjs docs for more info on these operators

const someEpic = action$ =>
  action$.ofType('SOME_ACTION')
    .do(() => sendAnalytics())
    .ignoreElements();

Anonymous Observable

This is a somewhat more "lightweight" solution since it doesn't use any operators other than ofType. I would caution against using this one though until you and your teammates have a solid grasp of RxJS and particularly creating custom/anonymous Observables. i.e. don't write code you don't understand.

const someEpic = action$ =>
  new Observable(() =>
    action$.ofType('SOME_ACTION')
      .subscribe(() => sendAnalytics()) // subscription is returned so it can be cleaned up
  );

This use case would be a great addition to the Recipes section of the docs, if someone ever has the time to PR it.


Btw, this is mostly an RxJS question where the stream just happens to be actions. You might find you get answers and better support long-term if you search or phrase your questions in the context of RxJS instead of redux-observable. Nearly all redux-observable questions are actually RxJS questions, which is great cause the knowledge is transferable!

like image 55
jayphelps Avatar answered Nov 14 '22 02:11

jayphelps