我正在使用ngrx,并将@Effect连接到LOAD_CONTRACT操作,该操作随后进行3个HTTP调用以获取数据。私有变量用于存储每个GET中的数据,因此最后可以使用包含3个检索到的对象的有效负载调用LoadContractSuccessAction。
下面的代码可以正常工作,错误处理也可以工作……但是我觉得可能存在一种更整齐或更更好的结构化方法。
我不知道是否所有的嵌套都是必要的,或者是否可以以某种方式将其弄平。我也不确定使用switchMap是否是最好的运算符。
对ngrx最佳实践有较深了解的人是否可以评论如何改进/简化以下内容??
private clientContractIds: IClientContractIds;
private contract: Contract;
private contractSummaryMonths: ContractSummaryMonth[];
private contractSummaryTotals: ContractSummaryTotals;
// Loads a contract and its summary months and totals.
@Effect()
loadContract$ = this.actions$.pipe(
ofType(ContractActionTypes.LOAD_CONTRACT),
map((action: IActionWithPayload<IClientContractIds>) => {
this.clientContractIds = {
client_id: action.payload.client_id,
contract_id: action.payload.contract_id
};
}),
// Get the contract.
switchMap(() => {
return this.contractService.getContract$(this.clientContractIds).pipe(
map(contract => (this.contract = contract)),
catchError(error => throwError(error)),
// Get the summary months.
switchMap(() => {
return this.contractService
.getContractSummaryMonths$(this.clientContractIds)
.pipe(
map(
contractSummaryMonths =>
(this.contractSummaryMonths = contractSummaryMonths)
),
catchError(error => throwError(error))
);
}),
// Get the summary totals.
switchMap(() => {
return this.contractService
.getContractSummaryTotals$(this.clientContractIds)
.pipe(
map(
contractSummaryTotals =>
(this.contractSummaryTotals = contractSummaryTotals)
),
catchError(error => throwError(error))
);
}),
// Call the success action with the payload objects.
switchMap(() => {
return of(
new LoadContractSuccessAction({
contract: this.contract,
contractSummaryMonths: this.contractSummaryMonths,
contractSummryTotals: this.contractSummaryTotals
})
);
})
);
}),
catchError(error => {
return of(new LoadContractFailAction(error));
})
);
答案 0 :(得分:1)
我要做的是让您的loadContract $效果在每个http调用中分配一个动作,而在执行您的http调用时每个动作分配一个效果。拆分通话可以更轻松地理解和调试。
它可能不是100%准确,但是可以给您一个大致的想法。
@Effect()
loadContract$ = this.actions$.pipe(
ofType(ContractActionTypes.LOAD_CONTRACT),
switchMap((action: IActionWithPayload<IClientContractIds>) => {
this.clientContractIds = {
client_id: action.payload.client_id,
contract_id: action.payload.contract_id
};
return [new action1(this.clientContractIds), new action2(this.clientContractIds), new action3(this.clientContractIds), new action4(this.clientContractIds)]
})
)
@Effect()
action1$ = this.actions$.pipe(
ofType(ContractActionTypes.action1),
switchMap((action: ACTION1) => {
return this.contractService
.getContractSummaryMonths$(action.payload.clientContractIds)
.pipe(
map(
contractSummaryMonths =>
(this.contractSummaryMonths = contractSummaryMonths)
),
catchError(error => throwError(error))
);
}))
我保留了您的代码,但我没有分配私有变量,而是为将使用化简器设置商店中数据的每个http调用调度成功操作。
答案 1 :(得分:0)
我使用forkJoin进行了重构,更干净了...
@Effect()
loadContract$ = this.actions$.pipe(
ofType(ContractActionTypes.LOAD_CONTRACT),
map((action: IActionWithPayload<IClientContractIds>) => {
return {
client_id: action.payload.client_id,
contract_id: action.payload.contract_id
};
}),
switchMap((clientContractIds: IClientContractIds) => {
return forkJoin(
// Get the contract.
this.contractService
.getContract$(clientContractIds)
.pipe(catchError(error => throwError(error))),
// Get the contract summary months.
this.contractService
.getContractSummaryMonths$(clientContractIds)
.pipe(catchError(error => throwError(error))),
// Get the contract summary totals.
this.contractService
.getContractSummaryTotals$(clientContractIds)
.pipe(catchError(error => throwError(error)))
).pipe(
map(([contract, contractSummaryMonths, contractSummaryTotals]) => {
return new LoadContractSuccessAction({
contract,
contractSummaryMonths,
contractSummaryTotals
});
}),
catchError(error => {
return of(new LoadContractFailAction(error));
})
);
})
);