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();
});
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.