I'm using Redux Observable and need to solve a timing issue when firing off actions from epics.
I have an array of items that I want to loop over for making AJAX calls on each one. Immediately after receiving the AJAX response, I want to fire off some actions. After all of the AJAX responses come back for each item in the original array, I want to fire off more actions.
How can I get these actions to fire immediately after the timer
expires even though the original array hasn't finished looping?
const someEpic = action$ => (
action$
.pipe(
ofType(SOME_ACTION),
switchMap(({ payload }) => (
from(payload) // This is an array of items
.pipe(
mergeMap(() => (
timer(5000) // This is my AJAX call
.pipe(
map(loadedAction),
)
)),
toArray(),
map(anotherAction),
)
))
)
)
Probably the easiest way is actually emitting actions using tap
wherever you want. This is assuming you have access to the store. For example:
tap(result => this.store.dispatch(...))
However a more "Rx" way would be splitting the chain using multicast
and then reemitting one part immediatelly (that's the loading progress) and the other half chaining with toArray()
to collect all results that would be then turn into another action signaling that loading is done.
import { range, Subject, of } from 'rxjs';
import { multicast, delay, merge, concatMap, map, toArray } from 'rxjs/operators';
const process = v => of(v).pipe(
delay(1000),
map(p => `processed: ${p}`),
);
range(1, 5)
.pipe(
concatMap(v => process(v)),
multicast(
() => new Subject(),
s => s.pipe(
merge(s.pipe(toArray()))
)
),
)
.subscribe(console.log);
Live demo: https://stackblitz.com/edit/rxjs6-demo-k9hwtu?file=index.ts