I would like to create an epic that listens for a explicit sequence of actions before doing work.
This epic also does not need to exist after it pletes the first time.
I'm picturing something like:
function doTheThing(action$) {
return action$
// The start of the sequence
.ofType(FIRST_ACTION)
// Do nothing until the second action occurs
.waitForAnotherAction(SECOND_ACTION)
// the correct actions have been dispatched, do the thing!
.map(() => ({ type: DO_THE_THING_ACTION }))
.destroyEpic();
}
Is something like this possible with redux-observable
?
I would like to create an epic that listens for a explicit sequence of actions before doing work.
This epic also does not need to exist after it pletes the first time.
I'm picturing something like:
function doTheThing(action$) {
return action$
// The start of the sequence
.ofType(FIRST_ACTION)
// Do nothing until the second action occurs
.waitForAnotherAction(SECOND_ACTION)
// the correct actions have been dispatched, do the thing!
.map(() => ({ type: DO_THE_THING_ACTION }))
.destroyEpic();
}
Is something like this possible with redux-observable
?
- 2 FYI nearly all redux-observable "how do I" questions are actually just RxJS questions where the data flowing just happens to be actions, but that's not super relevant. – jayphelps Commented Jul 11, 2017 at 23:18
-
Yep, thanks for the reminder. Added the
rxjs
tag. – Danny Delott Commented Jul 11, 2017 at 23:19 - 1 do you need access to the first action's payload? how bout the second one? – jayphelps Commented Jul 11, 2017 at 23:20
- Nope, neither payload is used. – Danny Delott Commented Jul 11, 2017 at 23:26
- Seems like an odd pattern IMO. I would personally put that sort of state in redux itself and no need for epics to be involved – jayphelps Commented Jul 11, 2017 at 23:31
2 Answers
Reset to default 6As @jayphelps pointed out in the ments there are a couple variants depending on whether you need access to the various events and if the events must be strictly ordered. So the following should all fit:
1) Strictly ordered don't care about events:
action$
.ofType(FIRST_ACTION)
.take(1)
.concat(action$.ofType(SECOND_ACTION).take(1))
.mapTo({ type: DO_THE_THING_ACTION })
2) Strictly ordered do care about events
action$
.ofType(FIRST_ACTION)
.take(1)
.concatMap(
a1 => action$.ofType(SECOND_ACTION).take(1),
(a1, a2) => ({type: DO_THE_THING_ACTION, a1, a2})
)
3) Non-strictly ordered (do or don't) care about events
Observable.forkJoin(
action$.ofType(FIRST_ACTION).take(1),
action$.ofType(SECOND_ACTION).take(1),
// Add this lambda if you *do* care
(a1, a2) => ({type: DO_THE_THING_ACTION, a1, a2})
)
// Use mapTo if you *don't* care
.mapTo({type: DO_THE_THING_ACTION})
This is how it looks with redux observables:
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/zip';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/take';
function doTheThing(action$) {
return Observable
// waits for all actions listed to plete
.zip(action$.ofType(FIRST_ACTION).take(1),
action$.ofType(SECOND_ACTION).take(1),
)
// do the thing
.map(() => ({ type: DO_THE_THING_ACTION }));
}