Эффект NgRx - внутренняя catchError выполняется несколько раз - PullRequest
1 голос
/ 05 июля 2019

У меня есть приложение Angulr с NgRx, внутри одного из моих эффектов у меня есть неожиданный эффект, который, оказывается, ожидается, но я не знаю, как это исправить.

Мой минимизированный код

@Effect()
detelete$ = this.actions$
  .pipe(
    ofType<fromActions.DeleteRequested>(fromActions.ActionTypes.DeleteRequested),
    map(action => action.payload.id),
    mergeMap(id =>
      combineLatest([
        of(id),
        this.rservice.deleteById(id)
          .pipe(
            catchError((err, caught$) => {
              this.store.dispatch(new fromActions.DeleteCancelled({id: id}));
              return caught$;
            })
          )
      ])
    ),
    map(([id, ]: [string, any]) => {
      return new fromActions.DeleteSuccess({id: id});
    }),
  );

Причина, по которой мои catchError не находятся на том же уровне, что и мои mergeMap, заключается в том, что мне нужно id в качестве полезной нагрузки для моего действия fromActions.DeleteCancelled.Кроме того, мой сервис возвращает только логическое значение, поэтому я использую combineLatest, чтобы сохранить его для моего onSuccess map.

Я испытываю то, что catchError выполняется несколько раз.Таким образом, отправляя мои действия с ошибками несколько раз.
Я обнаружил, что

Если вы вернете этот источник, наблюдаемое будет эффективно перезапускаться снова и повторять попытку

Inв этом случае source - это мое caught$.

Если внутри моего cacthError я вернусь

  return of(new fromActions.DeleteCancelled({id: id}));

Это все равно перейдет к моему onSuccess map.Я мог бы, возможно, проверить, является ли мой второй параметр внутри этого map типа os Action или boolean, но я думаю, что есть правильный способ справиться с этим, и я не знаю его.

StackBlitz (раскомментируйте subscribe, чтобы увидеть бесконечный цикл)

Спасибо.

1 Ответ

1 голос
/ 06 июля 2019

Вы могли бы рассмотреть этот подход.Ваш код может выглядеть следующим образом:

import { EMPTY, of, Observable } from 'rxjs';
...

@Effect()
delete$ = this.actions$.pipe(
  ofType<fromActions.DeleteRequested>(fromActions.ActionTypes.DeleteRequested),
  map(action => action.payload.id),
  switchMap((id) => this.rservice.deleteById(id).pipe(
    switchMap(result => {
      return result ? of(new fromActions.DeleteSuccess({id: id})) : EMPTY
    }),
    catchError(error => {
      return of(new fromActions.DeleteCancelled({id: id}))
    })
  )
)

, если ваш сервис возвращает true, поэтому отправляется действие DeleteSuccess, в противном случае пустая наблюдаемая, которая завершается немедленно.Поскольку EMPTY возвращает наблюдаемое, вы должны использовать switchMap, а также of, чтобы вернуть наблюдаемое действия DeleteSuccess.

В случае ошибки отправляется DeleteCancelled.

Другим подходом может быть использование @Effect({ dispatch: false }) и ручная отправка всех необходимых действий.

Надеюсь, это поможет.

...