Как я могу упорядочить избыточные действия после некоторого асинхронного действия, выполненного в наблюдаемом восстановлении? - PullRequest
0 голосов
/ 18 мая 2018

Контекст

У меня много действий в форме: LOAD_XYZ, LOAD_XYZ_FAIL, LOAD_XYZ_SUCCESS для различных элементов страницы, которые необходимо загрузить.

Мне часто хочетсявыполнить перенаправление (react-router) после загрузки какого-либо элемента, но так как redux-observable не возвращает обещание, я не могу выполнить перенаправление в своем компоненте - но вместо этого я должен сделать это, используя redux и push('...') изreact-router-redux.

Это, к сожалению, приводит к большому дублированию, поскольку у меня есть LOAD_XYZ и LOAD_XYZ_REDIRECT_TO версии одного и того же действия, плюс две эпопеи для каждого.

Это начинаетчувствую себя расточительным и слишком избыточнымЧтобы избежать избыточности и необходимости реализовывать несколько версий одного и того же эпоса.

Например, вместо этого я хотел бы иметь отдельное действие REDIRECT_TO, которое я могу выполнить после загрузки элемента.

Что-то вроде этих (воображаемых) решений:

dispatch(fetchUser(...)).then(redirectTo("..."))
dispatchSequence(fetchUser(...), redirectTo("..."))

Я знаю, redux-thunk может это сделать, но тогда я пропускаю все операторы rxjs.

1 Ответ

0 голосов
/ 23 мая 2018

Я, вероятно, копаюсь в опасных местах, но я нашел способ сделать это.

Сначала мы создаем промежуточное ПО, которое добавит завершение, наблюдаемое как метаданные к действиям.

import { Subject } from "rxjs";

export const AddListenerMiddleware = store => next => action => {
  const forkedAction = Object.assign({}, action, { meta: { listener: new Subject()}});
  next(forkedAction);
  return forkedAction.meta.listener.asObservable();
};

Так как это Subject, мы можем вызвать next для получения некоторого значения.Создание помощника notify позволяет нам уведомлять любых подписчиков о завершении действия (плюс передачу данных).

// notify doesn't consume but just emits on the completion observable
const notify = (action, fn) => source => 
  Observable.create(subscriber => 
    source.subscribe(emmission => {
      if (action.meta && action.meta.listener) {
        action.meta.listener.next(fn(emmission));
      }
      subscriber.next(emmission);
    })
  );

const fetchUserEpic = action$ =>
  action$.ofType(FETCH_USER)
    .mergeMap(action =>
      ajax.getJSON(`https://api.github.com/users/${action.payload}`)
      .map(response => fetchUserFulfilled(response))
      .pipe(notify(action, response => response.data))
    );

И теперь наша отправка возвращает наблюдаемое, с помощью которого мы можем выполнять стандартные операции rxjs.,Итак, наконец это становится возможным:

dispatch(fetchUser(...))
    .subscribe(({id}) => dispatch(redirectTo("/" + id)))

Отказ от ответственности: Используйте на свой страх и риск!

...