Диспетчер магазина несколько раз напоминает о http-эффекте - PullRequest
0 голосов
/ 04 июня 2019

Во время отправки мой эффект вызывается несколько раз, пока мой бэкэнд не ответит и данные не загрузятся. Мне нужна помощь в понимании того, как загрузить данные всего одним GET REQUEST, а затем загрузить из хранилища, если данные на самом деле уже присутствуют.

      this.cases$ = this.store
          .pipe(
            takeWhileAlive(this),
            select(selectImportTaskCasesData),
            tap(
              (cases) => {
                if (cases.length <= 0) {
                  this.store.dispatch(new ImportTaskLoadCasesAction());
                }
              }),
            filter((cases) => {
              return cases.length > 0;
            }),
            tap(() => {
              this.store.dispatch(new ImportTaskLoadCasesLoadedFromStoreAction());
            }),
            shareReplay()
          );

export const selectCasesData = createSelector(
  selectImportTaskCasesState,
  state => state ? state.cases : []
);

export const selectImportTaskCasesData = createSelector(
  selectCasesData,
  cases => {
    return cases.slice(0);
  }
);


 @Effect()
  ImportCasesLoad$: Observable<any> = this.actions$
    .pipe(
      ofType<ImportTaskLoadCasesAction>(ImportCasesActionTypes.ImportTaskLoadCasesAction),
      map((action: ImportTaskLoadCasesAction) => action),
      switchMap((payload) => {
        return this.importCases.get()
          .pipe(
            map(response => {
              return new ImportTaskLoadCasesSuccessAction({ total: response['count'], cases: response['results'] });
            }),
            catchError((error) => {
              this.logger.error(error);
              return of(new ImportTaskLoadCasesLoadErrorAction(error));
            })
          );
      })
    );

Ответы [ 2 ]

0 голосов
/ 04 июня 2019

Да, у меня есть редуктор для управления моим успехом, например:

    case ImportCasesActionTypes.ImportTaskLoadCasesSuccessAction:
  return {
    ...state,
    loading: false,
    cases: action.payload.cases,
    total: action.payload.total
  };

Это называется в моих эффектах.

0 голосов
/ 04 июня 2019

Работает ли нижеприведенное? Это предполагает, что у вас есть редуктор, который обрабатывает ImportTaskLoadCasesSuccessAction; Может быть, приведение рабочего примера поможет, поскольку есть немного предположений о том, как управляется состояние.

   this.cases$ = this.store
      .pipe(
        takeWhileAlive(this),
        select(selectImportTaskCasesData),
        tap(
          (cases) => {
            if (cases.length <= 0) {
              this.store.dispatch(new ImportTaskLoadCasesAction());
            }
          }),
        // personally, I would have the component/obj that is consuming this.cases$ null check the cases$, removed for brevity
        shareReplay()
      );

  export const selectCasesData = createSelector(
    selectImportTaskCasesState,
    state => state ? state.cases : []
  );

  export const selectImportTaskCasesData = createSelector(
    selectCasesData,
    cases => {
      return cases.slice(0);
    }
  );


 @Effect()
  ImportCasesLoad$: Observable<any> = this.actions$
    .pipe(
      ofType<ImportTaskLoadCasesAction>(ImportCasesActionTypes.ImportTaskLoadCasesAction),
      mergeMap(() => this.importCases.get()
          .pipe(
            map(response => {
              return new ImportTaskLoadCasesSuccessAction({
                total: response['count'],
                cases: response['results']
              });
            }),
            // catch error code removed for brevity
          );
      )
    );

Если вы хотите, чтобы звонок this.importCases.get() срабатывал только один раз, я предлагаю переместить диспетчер действий из .pipe(tap(...)). Поскольку это срабатывает каждый раз, когда происходит подписка.

Вместо этого установите this.cases $, чтобы всегда возвращать результат select(selectImportTaskCasesData),. Функционально вы, вероятно, хотите, чтобы он всегда возвращал массив. Но это зависит от вашего заданного желания. Враг пример ...

this.cases$ = this.store
  .pipe(
    takeWhileAlive(this),
    select(selectImportTaskCasesData),
  );

Отдельно, как в конструкторе, вы можете отправить this.store.dispatch(new ImportTaskLoadCasesAction());. Если вы хотите, чтобы он вызывался только тогда, когда case $ пуст, вы всегда можете заключить его в метод.

, например * * 1016

export class exampleService() {
  ensureCases(): void {
    this.store.pipe(
      select(selectImportTaskCasesData), 
      take(1)
    ).subscribe(_cases => {
      if (_cases && _cases.length < 1 ) {
        this.store.dispatch(new ImportTaskLoadCasesAction());
      }
    }),
  }
}
...