Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

redux-observable epic that doesn't send any new actions

Might be that I'm a noob and not fully understanding how this stuff should work yet, but I have an epic in redux-observable in which I want to use as a way to create a promise which will dispatch an action and wait for a different action before resolving. I've got it working by mapping the action to '__IGNORE__' but I really don't want to do that. Is there any way to just have an epic handle an action, but not pass anything else on?

Here's my code:

export const waitFor = (type, action) => new Promise((resolve, reject) => {
   const waitForResult = action$ => action$.ofType(type).do(() => resolve()).mapTo({type: "___IGNORE___"});
   registerEpic(waitForResult);

   action();
 });
like image 567
Ben Avatar asked Nov 03 '16 17:11

Ben


1 Answers

You can throw away any next'd values from an observable chain by using the .ignoreElements() RxJS operator

action$.ofType(type)
  .do(() => resolve())
  .ignoreElements();

Another way of doing this (no more right or wrong) is to create an anonymous Observable that just subscribes.

const waitForResultEpic = action$ => new Observable(observer =>
  action$.ofType(type)
    .subscribe(() => resolve())
);

This is implicitly returning the subscription we create, so that it's attached to the lifecycle of our rootEpic as well. Because we never call observer.next(), this epic never emits any values; just like ignoreElements().


Although you didn't ask, you may eventually notice that your epic will run forever, listening for that incoming action matching the type variable. This may not be not what you want, if you want to match once then complete.

You can accomplish that using .take(1) operator.

const waitForResult = action$ =>
  action$.ofType(type)
    .take(1)
    .do(() => resolve())
    .ignoreElements();

Or

const waitForResult = action$ => new Observable(observer =>
  action$.ofType(type)
    .take(1)
    .subscribe({
      next: () => resolve(),
      error: err => observer.error(err),
      complete: () => observer.complete()
    })
);

This will only match once per the life of the application--once received it will never do it again.

like image 180
jayphelps Avatar answered Nov 10 '22 21:11

jayphelps