-1

我正在使用 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));
  })
);
4

2 回答 2

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 调用调度成功操作,该调用将使用减速器在您的商店中设置数据。

于 2019-03-08T19:38:12.780 回答
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));
        })
      );
    })
  );
于 2019-03-08T20:32:09.600 回答