Несколько параллельных вызовов ajax и диспетчеризация избыточных действий после успешного завершения приводят к «неперехваченной ошибке: действия должны быть простыми объектами» - PullRequest
0 голосов
/ 30 июня 2018

Я новичок в rxjs и наблюдаемый редукс. Попытка создать эпос, который позволяет мне делать несколько параллельных вызовов ajax и отправляет соответствующие действия в случае успеха:

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() - создатель действия для действия с именем SAVE_POSTER. Но всякий раз, когда я запускаю свое приложение, никакие такие действия не отправляются. Вместо этого я получаю сообщение об ошибке в консоли браузера:

Uncaught Error: Действия должны быть простыми объектами. Использовать пользовательское промежуточное ПО для асинхронных действий.

1012 * редактировать * Попробовал упрощенную версию без 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); }) ) ), ), ); Приложение Просто для справки, у меня есть еще один эпос, который делает простой вызов ajax, который отлично работает: 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 Ответ

0 голосов
/ 30 июня 2018

Проблема в том, что я не возвращаю Наблюдаемое на моей внутренней карте. Изменение:

return Creators.savePoster(film, poster);

до

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

заставляет это работать.

Кстати, при использовании с 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));
  })
);

На самом деле это мое любимое решение.

...