I need to dispatch some actions in some order using redux-observable
however, it takes just last action to dispatch. Please see example:
export const fetchClientsEpic = (action$, { dispatch }) =>
action$
.ofType(fetchClients)
.mapTo(fetchClientsPending(true))
.mergeMap(() => {
return ajax
.getJSON('some/get/clients/api')
.map((clients: IClient[]) => {
return fetchClientsSuccess(
map(clients, (client, index) => ({
key: index,
...client,
})),
);
});
});
fetchClientsSuccess
is dispatched with clients but fetchClientsPending
not, I totally do not get it why. I could use dispatch
because I get it in params, but I feel it is not good solution(?). It should be done in the stream I guess. I am starting with RxJs and redux-observable. Is it possible to do?
Operators are chains of Observables where the input of one stream is the output of another. So when you use mapTo
you're mapping one action to the other. But then your mergeMap
maps that Pending action and maps it to that other inner Observable that does the ajax and such, effectively throwing the Pending action away. So think of RxJS as a series of pipes where data flows through (a stream)
While there is no silver bullet, in this particular case what you want to achieve can be done by using startWith
at the end of your inner Observable
export const fetchClientsEpic = (action$, { dispatch }) =>
action$
.ofType(fetchClients)
.mergeMap(() => {
return ajax
.getJSON('some/get/clients/api')
.map((clients: IClient[]) => {
return fetchClientsSuccess(
map(clients, (client, index) => ({
key: index,
...client,
})),
);
})
.startWith(fetchClientsPending(true)); // <------- like so
});
This is in fact the same thing as using concat
with of(action) first
, just shorthand.
export const fetchClientsEpic = (action$, { dispatch }) =>
action$
.ofType(fetchClients)
.mergeMap(() => {
return Observable.concat(
Observable.of(fetchClientsPending(true)),
ajax
.getJSON('some/get/clients/api')
.map((clients: IClient[]) => {
return fetchClientsSuccess(
map(clients, (client, index) => ({
key: index,
...client,
})),
);
})
);
});
That said, I would recommend against synchronously dispatching another action to set the state that fetching is pending and instead rely on the original fetchClients
action itself for the same effect. It should be assumed by your reducers that if such an action is seen, that some how the fetching still start regardless. This saves you the boilerplate and helps a bit on micro-perf since you don't need to run through the reducers, epics, and rerender twice.
There's no rules though, so if you feel strongly about this, go for it :)