Отменить эффект takeUntil при запуске другого действия в rxjs

avatar
vikneshwar
8 августа 2021 в 21:47
111
1
0

Я использую redux-observables для обработки эффектов для моего приложения react/redux. Я столкнулся с ситуацией, когда я хочу отменить эффект takeUntil, когда я запускаю избыточное действие.

Вот пример кода

const productOrderPlace = (action$, state$) => {
  return action$.pipe(
    ofType(action.PRODUCT_ORDER_PLACE),
    mergeMap(() => {
      return api.productOrderPlace(state$.value).pipe(mergeMap((res) => {
        return merge(of(action.getStatus()).pipe(delay(res.beginAt)), of(action.getStatusExpired()).pipe(delay(15000)))
      }));
    })
  );
};

const getStatus = (action$, state$) => {
  return action$.pipe(
    ofType(action.GET_STATUS),
    takeUntil(merge(
      action$.pipe(ofType(actions.GET_STATUS_EXPIRED)),
      action$.pipe(ofType(actions.GET_STATUS_DONE))
    )),
    mergeMap(() => {
      return api.getStatus(state$.value).pipe(mergeMap(() => {
       // this is the polling call here i would be triggering GET_STATUS again after a specific interval from the current polling response  or call GET_STATUS_DONE if response contains success status
      }));
    })
  );
}

Итак, в основном, что я делаю, это когда пользователь нажимает кнопку «Заказать», будет вызван API productOrderPlace , а затем начнется опрос статуса заказа, вызвав getStatus, здесь для опроса я не использую рецепт по умолчанию из rxjs с интервалом или таймером, потому что интервал опроса не совпадает, следующий интервал опроса будет взят из предыдущего ответа на опрос. И первый вызов опроса должен быть вызван через несколько секунд на основе beginAt в ответе productOrderPlace. И максимальное время, которое пользователь может ждать, составляет 15 секунд, поэтому я запускаю таймер, как только получаю ответ productOrderPlace

.

Итак, теперь я столкнулся с проблемой, когда запускается событие с истекшим сроком действия, пользователю отображается ошибка. Однако пользователь может снова нажать кнопку «Заказать» и снова разместить заказ, в таком случае getStatus не будет выполнено, потому что я использовал takeUntil, а действие внутри takeUntil уже запущено, поэтому я хотел отменить эффект takeUntil, когда пользователь снова нажимает кнопку «Заказать» (т. е. когда PRODUCT_ORDER_PLACE снова запускается)

Источник
Jensen
9 августа 2021 в 13:42
0

С чего начинается голосование? я не понимаю, как ваши две функции используют друг друга

Jensen
9 августа 2021 в 13:54
0

почему productOrderPlace вызывает сам себя, но только с одним аргументом?

vikneshwar
9 августа 2021 в 18:02
0

@Jensen, на самом деле это api.productOrderPlace, это не та же функция, я внес несколько изменений, когда разместил ее здесь, потому что я не хочу оставлять код своей компании на общедоступном форуме, это может привести к нарушению регистра, но этот код является общим. суть того, что я пытаюсь. Отредактировал код выше. И опрос не является явным, я упомянул в комментарии, что я снова вызываю GET_STATUS на основе статуса из API. Спасибо

Ответы (1)

avatar
Andrei Gătej
9 августа 2021 в 21:05
0

Я думаю, это может быть способом решить эту проблему:

const getStatus = (action$, state$) => {
  return action$.pipe(
    ofType(action.GET_STATUS),

    mergeMap(() => {
      return api.getStatus(state$.value).pipe(mergeMap(() => {/* ... */}));
    }),

    // Placing the `takeUntil` operator here since the `mergeMap` operator
    // won't pass along the *complete* notification unless all of the active
    // inner observables complete too.
    takeUntil(
      action$.pipe(
        ofType(action.PRODUCT_ORDER_PLACE),
        switchMap(
          () => merge(
            action$.pipe(ofType(actions.GET_STATUS_EXPIRED)),
            action$.pipe(ofType(actions.GET_STATUS_DONE))
          )
        )
      )
    ),
  );
}

Используя switchMap, мы повторно подписываемся каждый раз, когда выполняется действие PRODUCT_ORDER_PLACE.