Полная функция перед удаленной работой в NgRx

У меня проблема с состоянием гонки в NgRx. В приведенном ниже примере я асинхронно представляю диалог загрузки примерно одновременно с запуском асинхронной удаленной операции. Но удаленная операция может завершить и запустить dismissLoadingDialog() до того, как диалоговое окно загрузки будет полностью построено, что приведет к ошибке консоли.

Какой может быть хорошая стратегия в NgRx для завершения presentLoadingDialog() до начала удаленной операции?

@Effect() fetchServerData$ = this.actions$.pipe(
    ofType<FetchServerData>(ActionTypes.FetchServerData),
    switchMap(action => {
      this.presentLoadingDialog('...loading');
      return this.dataService.fetchData(action.payload).pipe(
        map(result => {
          this.dismissLoadingDialog();            
          return new FetchServerDataSuccess(result);
        }),
        catchError(err => of(new FetchServerDataFail(err)))
      );
    })
  );


async presentLoadingDialog(message: string): Promise<void> {
    this.isLoading = true;
    return this.loadingCtrl
      .create({
        duration: 5000,
        message: message
      })
      .then(loadingDialog => {
        loadingDialog.present().then(() => {
          if (!this.isLoading) {
            loadingDialog.dismiss();
          }
        });
      });
  }

  async dismissLoadingDialog() {
    this.isLoading = false;
    if (!isNullOrUndefined(this.loadingCtrl)): Promise<boolean> {
      return this.loadingCtrl.dismiss();
    }
  }

2 ответа

Решение

Контроллер загрузки Ionic createМетод возвращает обещание, которое разрешается, когда создание загрузчика завершено. Поэтому вы можете использовать его в цепочке наблюдаемых эффектов:

presentLoadingDialog(message: string) {
  const loader = this.loadingCtrl
    .create({
      duration: 5000,
      message: message
    });
  return loader.present();
}

dismissLoadingDialog() {
  this.loadingCtrl.dismiss();
}

@Effect() fetchServerData$ = this.actions$.pipe(
  ofType<FetchServerData>(ActionTypes.FetchServerData),
  switchMap(action => forkJoin(from(this.presentLoadingDialog('...loading'), of(action)),
  switchMap(([_, action]) => this.dataService.fetchData(action.payload).pipe(
    tap(() => this.dismissLoadingDialog()),
    map(result => new FetchServerDataSuccess(result)),
    catchError(err => {
      this.dismissLoadingDialog();
      return of(new FetchServerDataFail(err))
    })
  ))
);

Стандарт, который я видел, - это у вас есть флаги загрузки и загрузки в вашем состоянии. Когда вы отправляете действие загрузки, редуктор обновляет состояние с помощью loading: true и loaded: false до того, как действие запустит HTTP-запрос. Затем действие переключает сопоставления на действие, которое обновляет состояние с помощью ответа и loading: false и loaded: true.

Затем в вашем компоненте у вас есть селектор для флага загрузки и вы подписываетесь на него, чтобы открывать и закрывать диалог.

this.loadingSub = loadings$.subscribe(loading => {
  if (loading) {
    this.presentLoadingDialog('...loading');
  } else {
    this.loadingDialog.dismiss();
  }
});

отписаться в onDestroy

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

Другие вопросы по тегам