Multipe ajax calls in parallel and dispatching redux actions after success leads to “Uncaught Error: Actions must be plain objects”

Multi tool use
Multi tool use


Multipe ajax calls in parallel and dispatching redux actions after success leads to “Uncaught Error: Actions must be plain objects”



I am new to rxjs and redux-observable. Trying to create an epic that allows me to do multiple parallel ajax calls and dispatches respective actions on success:


const loadPosters = (action$) => action$.pipe(
ofType(Types.LOAD_FILMS_SUCCESS),
switchMap(({ films }) =>
forkJoin(films.map(film =>
ajax
.getJSON(`https://api.themoviedb.org/3/search/movie?query=${film.title}`)
.pipe(
map(response => {
const [result] = response.results;
const poster = `http://image.tmdb.org/t/p/w500/${result.poster_path}`;
return Creators.savePoster(film, poster);
})
),
))
),
);



Creators.savePoster() is an action creator for an action named SAVE_POSTER. But, whenever i run my application, no such action is dispatched. Instead i get an error message in browser console:


Creators.savePoster()


SAVE_POSTER



Uncaught Error: Actions must be plain objects. Use custom middleware
for async actions.



Tried a simplified version without forkJoin, sadly yielding the same result:


forkJoin


const loadPosters = (action$) => action$.pipe(
ofType(Types.INIT_SUCCESS),
mergeMap(({ films }) =>
films.map(film =>
ajax
.getJSON(`https://api.themoviedb.org/3/search/movie?query=${film.title}`)
.pipe(
map(response => {
const [result] = response.results;
const poster = `http://image.tmdb.org/t/p/w500/${result.poster_path}`;
console.log(Creators.savePoster(film, poster));
return Creators.savePoster(film, poster);
})
)
),
),
);



Appendix



Just for reference, I have another epic which does a simple ajax call which works fine:


const loadFilms = action$ => action$.pipe(
ofType(Types.INIT_REQUEST),
mergeMap(() =>
ajax
.getJSON('https://star-wars-api.herokuapp.com/films')
.pipe(
map(response => Creators.initSuccess(response))
),
),
);




1 Answer
1



The problem is that i don't return an Observable in my inner map. Changing:


return Creators.savePoster(film, poster);



to


return of(Creators.savePoster(film, poster));



makes it work.



By the way, if used with forkJoin it's also possible (and in my case better) to take the mapped results after all requests resolved and dispatch a single action instead of multiple ones:


forkJoin


const loadPosters = (action$) => action$.pipe(
ofType(Types.INIT_SUCCESS),
mergeMap(({ films }) =>
forkJoin(
films.map(film =>
ajax
.getJSON(`https://api.themoviedb.org/3/search/movie?query=${film.title}`)
.pipe(
map(response => ({ film, response }))
)
),
)
),
mergeMap(data => {
const posters = data.reduce((acc, { film, response}) => ({
...acc,
[film.id]: `http://image.tmdb.org/t/p/w500/${response.results[0].poster_path}`,
}), {});
return of(Creators.savePosters(posters));
})
);



In fact this is my favorite solution so far.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

oiWhR,A4
RKcE,28

Popular posts from this blog

Delphi Android file open failure with API 26

.

Amasya