forkEpic, redux-observable 1.0.0-alpha.2, машинописный текст

У меня есть одна эпопея

type GetRailwaysEpic = Epic<GetRailwaysActions, AppState>;

const getRailwaysEpic: GetRailwaysEpic = (action$, state$) =>
  action$.pipe(
    filter(isActionOf(getRailways.request)),
    switchMap(a =>
      getRailways(state$.value.mileages.filters.date)
        .then(getRailways.success)
        .catch(getRailways.failure)
    )
  );

когда я вызываю в любом месте actions.getRailways.request (), он работает так, как ожидалось (сначала действие ЗАПРОС, затем УСПЕХ из НЕИСПРАВНОСТИ)

У меня есть еще одна эпопея

const initEpic: Epic<FiltersActions, AppState> = (action$, state$) =>
  action$.pipe(
    filter(isActionOf(init)),
    switchMap(({ payload: { date, depotId, locTypeId, railwayId } }) =>
      of(selectDate(date)).pipe(
        concat(
          forkEpic(getRailwaysEpic, state$, getRailways.request())
        )
      )
    )
  );

моя функция ForkEpic:

function forkEpic<T extends Action, S>(
  epicFactory: Epic<T, S>,
  state$: StateObservable<S>,
  ...actions: T[]
) {
  const actions$ = ActionsObservable.of(...actions);
  return epicFactory(actions$, state$, null);
}

Что я хочу: действие 'init' -> действие 'selectDate' -> действие 'getRailways.request' -> 'getRailways.success' | действие getRailways.failure

Что я вижу: действие «init» -> действие «selectDate» -> «getRailways.success» | действие getRailways.failure

Действие getRailways.request где-то отсутствует. Что я делаю не так?

P.S. getRailways - функция, возвращающая обещание P.P.S. Я нашел здесь аналогичный вопрос Как связать асинхронные действия и ждать результата без store.dispatch Но это не то, что я действительно ищу.


person abdurahmanus    schedule 21.05.2018    source источник


Ответы (1)


Таким образом, проблема в том, что функция forkEpic вызывает getRailwaysEpic локально и, поскольку она использует switchMap, она проглатывает действие «запрос», таким образом не позволяя ему достичь epicMiddleware.

Лучшее решение - объединить действие «выбрать» с потоками действий «запрос» и вернуть его, чтобы оно было правильно передано epicMiddleware обратно в хранилище, а затем оно будет перехвачено и обработано getRailwaysEpic из потока действий $.

Вот рабочее решение в песочнице кода: https://codesandbox.io/s/375z2qwv1

Вот ответственный код:

const requestEpic = action$ =>
  action$.pipe(
    filter(a => a.type === 'request'),
    switchMap(a => from(makeRequest()).pipe(map(success)))
  );

const initEpic = action$ =>
  action$.pipe(
    filter(a => a.type === 'init'),
    concatMap(a => of(select(), request()))
  );

const rootEpic = combineEpics(requestEpic, initEpic);
const epicMiddleware = createEpicMiddleware(rootEpic);

// 1
// store.dispatch(init());
// should be:
// init -> select -> request -> success

// 2
// store.dispatch(request());
// should be:
// request -> success
person Piotrek Witek    schedule 23.05.2018
comment
Я хочу здесь - использовать 2 эпика независимо, я имею в виду, чтобы иметь возможность отправлять оба действия (запрос и инициализацию). Если я буду использовать concat, у меня будет бесконечный цикл. - person abdurahmanus; 23.05.2018
comment
@abdurahmanus Я адаптировал ответ, чтобы показать правильный способ достижения того, что вы ищете, IMO ваша forkEpic функция в исходном вопросе не нужна, добавляя ненужную абстракцию, где правильный подход состоял бы в том, чтобы позволить потоку эпоса вернуться в магазин а затем отправляться через epicMiddleware и инициализировать другой эпик, который ожидает действия запроса. - person Piotrek Witek; 23.05.2018
comment
Спасибо, это работает! Я просто хотел найти способ объединить несколько эпиков, похожих на redux-thunk. Может, мне нужно пересмотреть то, как я думал. - person abdurahmanus; 24.05.2018
comment
@abdurahmanus определенно вам нужно, я также переключался с redux-thunk, поэтому для меня самая большая разница заключается в том, что я считаю, что эпики всегда разделены, поэтому вы не переходите от одного эпика к другому напрямую, но вы возвращаете действие, и это действие перейдет к еще одна эпопея и включи ее. PS: Пожалуйста, примите ответ - person Piotrek Witek; 24.05.2018