在学习Angular和NGRX时,遇到了我认为是常见问题的简单示例,但在理解Redux存储\效果模式中实现控制逻辑的最佳方法时遇到了麻烦。
一般流程:
用户输入信用卡信息,点击“付款”按钮>从组件中分配“ GetTokenAction”>向外部第三方API发出Http请求以标记化>如果成功将该信息提交给Payment API
这是我最近的尝试:
@Effect() getToken$ = this.actions$
.ofType(TokenizerActions.GET_TOKEN)
.pipe(switchMap((action: TokenizerActions.GetTokenAction) => {
return this.TokenizerApiService.getToken(action.payload)
.pipe(
map(tokenResponse => {
console.log(tokenResponse);
// service will return 200 with "declined" status. In this case I want to treat it like an Error.
if (tokenResponse.results.Error != null) {
return new TokenizerActions.GetTokenFailedAction(tokenResponse.results.Error.messages);
}
// What is best practice here? Call Payment Service? Dispatch Actions? Where should this mapping logic live?
const paymentRequest: PaymentRequest = new PaymentRequest();
paymentRequest.token = tokenResponse.results.token;
paymentRequest.amount = action.payload.amount;
paymentRequest.customerNumber = action.payload.customerNumber;
paymentRequest.correlationId = tokenResponse.results.correlation_id;
// this does not work, "dispatched an invalid action: undefined" error.
mergeMap((payReq: PaymentRequest) => [new paymentActions.MakePaymentAction(paymentRequest),
new TokenizerActions.GetTokenSuccessAction(tokenResponse.results.token)]);
}),
catchError(error => of(new TokenizerActions.GetTokenFailedAction(error)))
);
}));
constructor(
private actions$: Actions,
private TokenizerApiService: TokenizerApiService,
private paymentApiService: PaymentApiService
) { }
问题/考虑事项:
效果是否适合处理此问题?第一个工作版本具有控制流和调度多个动作的组件,也可以在服务中处理该组件,不确定哪种是最佳实践。
Effects模式中错误通知的首选方法是什么?在线和示例应用程序中有很多简单的示例,但是我很难将其转换为稍微复杂的示例(检查响应,然后抛出错误并根据需要停止处理)。当前,应用程序正在执行以下操作:
<span class="error" *ngFor="let error of tokenErrors$ | async">{{error.description}}</span>
<span class="error" *ngFor="let error of paymentErrors$ | async">{{error.description}}</span>
<div class="success" *ngIf="(payment$ | async)?.transactionStatus === 'approved'">Success</div>
this.paymentErrors$ = this.store.select(state => state.payment.paymentErrorMessages);
this.tokenErrors$ = this.store.select(state => state.token.tokenErrorMessages);
this.payment$ = this.store.select(state => state.payment.paymentStatus);
可以更简单吗?错误应合并为一个PayError数组吗?如果订阅了组件级别,有什么收获吗?还是要在效果级别中全部处理?
答案 0 :(得分:2)
首先,不要直接执行箭头功能,而是创建选择器。
第二,使用一个选择器(而不是3个不同的选择器)选择该组件所需的ViewModel(transactionInfo
)。您可以组合多个选择器来实现。
例如,可以使用*ngIf
将结果推到模板中更高的位置
<ng-container *ngIf="transactionInfo$ | async as transactionInfo">
<span class="error" *ngFor="let error of tokenErrors">{{error.description}}</span>
<span class="error" *ngFor="let error of transactionInfo.paymentErrors">{{error.description}}</span>
<div class="success" *ngIf="transactionInfo.transactionStatus === 'approved'">Success</div>
</ng-container>