NgRx 远程操作前的完整功能

Complete Function Before Remote Operation in 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();
    }
  }

我看到的标准是你的州有加载和加载标志。当您分派加载操作时,reducer 在操作触发 http 请求之前使用 loading: true 和 loaded: false 更新状态。该动作然后切换映射到一个动作,该动作使用响应和加载更新状态:false 和加载:true。

然后在您的组件中有一个用于加载标志的选择器并订阅它以打开和关闭对话框

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

在 onDestroy 取消订阅

应该由您的组件来显示 UI 组件,我认为调用加载对话框的操作不是操作问题。利用状态管理的核心来调用 UI 组件不是我推荐的模式。

Ionic 的 LoadingController create 方法 returns 加载程序创建完成时解析的 Promise。因此,您可以在效果的 Observable 链中使用它:

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))
    })
  ))
);