I'am currently switched from promises to observables. I am using Redux-Observable for my react app. Basically, I am looking for the best operator that will enable mutliple, concurrent ajax calls and return the responses when all the observables have sucessfully finished executing. Here is a code snippet from my app.
let epicPostAd = (action$, store, {ajax}) =>
action$.ofType(POST_AD)
.debounceTime(1000)
.mergeMap(({ payload }) =>
ajax(generateAjaxRequestSetting(POSTS_URL, 'post', payload,CT_JSON))
.map(response => postAdSuccessful(response))
.catch(e => Observable.of(postAdUnsuccessful(e.xhr.response)))
.takeUntil(action$.ofType(LOCATION_CHANGE))
)
It is a simple ajax request that posts given ad and dispatches POST_AD_SUCCESSFUL
when response is 201 else dispatches POST_AD_UNSUCCESSFUL
on error.
But the issues is I want to make subsequent ajax observable stream when there is a response. Such as
.map(response => /* start a stream of ajax observables then process the response */)
I will appreciate if you show me the optimal way of achieving this.
Sounds like you're looking for the forkJoin
operator.
It will subscribe to all the Observables you pass to it and after they all complete, it will emit the last value from each inside an array.
It wasn't entirely clear where in your Epic you wanted to do this, so I just made a generic example:
const somethingEpic = (action$, store, { ajax }) =>
action$.ofType(SOMETHING)
.mergeMap(() =>
Observable.forkJoin(
ajax('/first'),
ajax('/second'),
ajax('/third')
)
.do(results => {
// the results is an array, containing each
const [first, second, third] = results;
console.log(first, second, third);
})
.map(results => ({
type: 'SOME_RESULTS',
results
}))
);
Technically, it supports a final resultSelector
argument you can use instead of using the map
operator after it, but I tend not to use it because I've found it's less clear with only negligible performance benefits in common redux-observable style cases. But it's still good to know. Can be handy for more "data-normalization" stuff rather than "transform this into an action" stuff.
const somethingEpic = (action$, store, { ajax }) =>
action$.ofType(SOMETHING)
.mergeMap(() =>
Observable.forkJoin(
ajax('/first'),
ajax('/second'),
ajax('/third'),
results => ({
type: 'SOME_RESULTS',
results
})
)
);
ALSO, if you're asking yourself "what operator do I use?" you should try the operator wizard located in the documentation: http://reactivex.io/rxjs/
Scroll down to the part that says:
Do you need to find an operator for your problem? Start by choosing an option from the list below:
- I have one existing Observable, and...
- I have some Observables to combine together as one Observable, and...
- I have no Observables yet, and...
Hint: open your DevTools to experiment with RxJS.
Though in this case, forkJoin
is correctly suggested but when you click on it, it isn't yet documented :sadface: But a google search would present many different websites explaining what it does and how to use it (in RxJS and in other Rx implementations in other languages). Like this helpful website
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With