如何使用switchmap、pipe、map和catchError实现通用帮助程序来处理错误



这是一个具有在当前代码中重复多次的模式的代码

loadBasicStateInfo$ = createEffect(() => this.actions$.pipe(
ofType(actions.loadBasicStateInfo),
switchMap(args => this.configurationService.getBasicStateInfo()
.pipe(
map(response => actions.loadBasicStateInfoComplete({ basicStateInfo: new BasicStateInfo(response.result) })),
catchError(() => of(actions.loadBasicStateInfoFailure({ error: 'fail' })))
)
)
));
loadClientServerMinutesOffset$ = createEffect(() => this.actions$.pipe(
ofType(actions.loadClientServerMinutesOffset),
switchMap(args => this.configurationService.getClientServerMinutesOffset()
.pipe(
map(response => actions.loadClientServerMinutesOffsetComplete({ clientServerMinutesOffset: response.result })),
catchError(() => of(actions.loadClientServerMinutesOffsetFailure({ error: 'fail' })))
)
)
));
loadSetting$ = createEffect(() => this.actions$.pipe(
ofType(actions.loadSettings),
switchMap(args => this.configurationService.getSettingsByNamesForUser(args.settingNames)
.pipe(
map(response => actions.loadSettingsCompleted({ settings: response.result })),
catchError(() => of(actions.loadSettingsFailure({ error: 'fail' })))
)
)
));

我对打字脚本很陌生,但我想重构成一些辅助方法,这就是我的起点

import { Actions, createEffect } from '@ngrx/effects';
import { catchError, switchMap } from 'rxjs/operators';
class effectHelper {
public create(act: Actions, type: any, apiCall: any, methodForMap: any, methodForError: any) {
return createEffect(() => act.pipe(
ofType(type),
switchMap(apiCall.pipe(
map(methodForMap)),
catchError(methodForError))
));
}
}

我如何实现像上面这样的通用帮助程序?这可能吗?如何实现这一目标?

更新

action是以这种方式声明的ngrx操作

export const loadClientServerMinutesOffset = createAction('[Configuration] Load Client Server Minutes Offset');
export const loadClientServerMinutesOffsetComplete = createAction('[Configuration] Load Client Server Minutes Offset Completed',
props<{ clientServerMinutesOffset: number }>());
export const loadClientServerMinutesOffsetFailure = createAction('[Configuration] Load Client Server Minutes Offset Failed', props<{ error: any }>());

我对NgRx不太熟悉,但它与我熟悉的Redux非常相似。

我们想要为给定的API调用创建一组三个操作。我们需要知道动作的基本名称,API函数,以及如何从API响应映射到"的数据;完整的";行动,即response => ({ clientServerMinutesOffset: response.result })

我不确定的是Actions对象来自哪里,以及它应该是父createApiActions函数的参数还是传递给effect函数的参数。

使用泛型键入this最令人讨厌的部分是createAction函数使用类型NotAllowedCheck<P>来验证参数。如果你只有一个通用的P extends object,那么你会得到P不可分配给NotAllowedCheck<P>的错误。mapResponse基本上只是(response: Res) => R,但为了避免这些错误,我不得不将其定义为FunctionWithParametersType<[Res], R & NotAllowedCheck<R>>

import { Actions, createEffect, ofType } from "@ngrx/effects";
import { createAction, FunctionWithParametersType, NotAllowedCheck } from "@ngrx/store";
import { catchError, switchMap, map } from "rxjs/operators";
import { of, Observable } from "rxjs";
const createApiActions = <Args extends object, Res, R extends object>(
actions: Actions,
category: string,
apiCall: (args: Args) => Observable<Res>,
mapResponse: FunctionWithParametersType<[Res], R & NotAllowedCheck<R>>
) => {
const pending = createAction(
`[${category}] Pending`,
(args: Args & NotAllowedCheck<Args>) => args
);
const complete = createAction<string, [Res], R>(
`[${category}] Complete`,
mapResponse
);
const failure = createAction(
`[${category}] Failure`, 
() => ({ error: "fail" })
);
const effect = createEffect(() =>
actions.pipe(
ofType(pending),
switchMap((args) =>
apiCall(args).pipe(
map((response) => complete(response)),
catchError(() => of(failure()))
)
)
)
);
return {
pending,
complete,
failure,
effect
};
};

该辅助对象创建一组三个动作创建者和效果。效果的结构与以前相同,但现在我们可以用变量替换您的硬编码操作。

你会这样使用它:

const loadSettings = createApiActions(
actions,
'loadSettings',
(args: {settingNames: string[]}) => this.configurationService.getSettingsByNamesForUser(args.settingNames),
(response: SomeType) => ({ settings: response.result }),
)
loadSettings.pending({settingNames: ["someSetting"]})

在这一点上,我已经意识到,在不需要任何参数的情况下,将Args定义为object是不起作用的。所以我的类型需要更多的工作。但我将把这件事留给你。

最新更新