使用 ngrx 在一个 @Effect 中构造多个 HTTP 调用的最干净的方法是什么
What is the cleanest way of structuring multiple HTTP calls within one @Effect using ngrx
我正在使用 ngrx 并将 @Effect 连接到 LOAD_CONTRACT 操作,然后进行 3 次 HTTP 调用以获取数据。私有变量用于存储来自每个 GET 的数据,因此最后可以使用包含 3 个检索到的对象的有效负载调用 LoadContractSuccessAction。
我下面的代码工作正常,错误处理也工作正常...但我觉得可能有更简洁或更好的结构化方法。
我不知道是否所有的嵌套都是必要的,或者是否可以通过某种方式把事情弄平。我也不确定使用 switchMap 是否是最好的运算符。
对 ngrx 最佳实践有更好了解的人能否评论以下内容 improved/simplified...?
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));
})
);
我要做的是让您的 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))
);
}))
我保留了您的代码,但我没有分配私有变量,而是为每个使用 reducer 设置商店中数据的 http 调用发送成功操作。
我使用 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));
})
);
})
);
我正在使用 ngrx 并将 @Effect 连接到 LOAD_CONTRACT 操作,然后进行 3 次 HTTP 调用以获取数据。私有变量用于存储来自每个 GET 的数据,因此最后可以使用包含 3 个检索到的对象的有效负载调用 LoadContractSuccessAction。
我下面的代码工作正常,错误处理也工作正常...但我觉得可能有更简洁或更好的结构化方法。
我不知道是否所有的嵌套都是必要的,或者是否可以通过某种方式把事情弄平。我也不确定使用 switchMap 是否是最好的运算符。
对 ngrx 最佳实践有更好了解的人能否评论以下内容 improved/simplified...?
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));
})
);
我要做的是让您的 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))
);
}))
我保留了您的代码,但我没有分配私有变量,而是为每个使用 reducer 设置商店中数据的 http 调用发送成功操作。
我使用 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));
})
);
})
);