Полная функция перед удаленной работой в 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
Отображение компонентов пользовательского интерфейса должно зависеть от ваших компонентов, я думаю, что действия, вызывающие диалоги загрузки, не являются проблемой. Я бы не рекомендовал использовать самую суть управления состоянием для вызова компонентов пользовательского интерфейса.