繁体   English   中英

NGRX 效果 / RXJS:循环 API 调用和操作

[英]NGRX Effects / RXJS: Loop API Calls and Actions

目标是循环遍历 ID 数组,并为每个 ID 进行 API 调用并使用结果发送一个 Action。

我目前的想法:

someEffect$ = createEffect(() => this.actions$.pipe(
    ofType(someAction),
    withLatestFrom(this.store.select(selectIds)),
    switchMap(([_, ids]) => {
      return forkJoin(ids.map(id =>
        this.service.getData(id))).pipe(
        map(result => {
          return actionSuccess({result});
        }),
        catchError((error: HttpErrorResponse) => {
          return of(actionError({error}));
        })
      )
    })
  ));

这有点管用,但有两种不良行为:

  1. actionSuccess 仅被调度一次,所有 api 调用的结果作为一个数组。 我要为每个 API 呼叫发送一次。

将 forkJoin 替换为 merge 会触发每个 ID 的操作,但随后 API 调用不再发生,因此必须有更多。

  1. forkJoin 等待所有 API 调用完成,然后才继续。 我想在每次 getData() 完成后立即发送 actionSuccess。

我知道你在问如何在effects中调度循环遍历数组的动作,但是,例如,如果让组件处理循环操作,那么你将为每个 id 调度一个成功的动作。

成分:

loadCustomerById(): void {
  this.store.select(ClientSelectors.selectIds).subscribe((ids) => {
    if (ids.length) {
      for (const id of ids) {
       this.store.dispatch(ClientActions.loadCustomerById({ payload: id }));
      }
    }
  })
}

效果:

loadCustomerById$ = createEffect(() => this.actions$.pipe(
    ofType(loadCustomerById),  
    // you already get the id from action
    // no need of withLastestFrom  
    mergeMap(({ payload: id }) => 
      this.service.getData(id).pipe(
        map((response) => ClientActions.loadCustomerByIdSuccess({ payload: response })),
        catchError((error) => of(ClientActions.loadCustomerByIdFail({ error })))
      )
    ) 
  ));

使用 merge 而不是 forkJoin - 有关更多信息,请参阅https://timdeschryver.dev/snippets#multiple-service-calls-from-an-effect

refresh$ = createEffect(() =>
  this.actions$.pipe(
    ofType(CustomerActions.refresh),
    exhaustMap(({ customerIds }) =>
      merge(
        ...ids.map((id) =>
          this.customersService.getCustomer(id).pipe(
            map(CustomerActions.getCustomerSuccess),
            catchError((err) =>
              of(CustomerActions.getCustomerFailed(id, err.message)),
            ),
          ),
        ),
      ),
    ),
  ),
)

我建议将 Array 的 Observable 转换为 Observable,它使用from发出 Array 中的所有元素:

someEffect$ = createEffect(() => this.actions$.pipe(
  ofType(someAction),
  withLatestFrom(this.store.select(selectIds)),
  switchMap(([_, ids]) => from(ids)),
  mergeMap(id => this.service.getData(id).pipe(
    map(result => actionSuccess({ result })),
    catchError(error => of(actionError({ error })))
  ))
));

然而,根据ids的长度,这可能很快变得站不住脚,并且可能值得重构您的后端以接受批处理调用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM