Angular NGRX : Use withLatestFrom to call api only once. 但是, 'loader' 仍然设置为 true

标签 angular rxjs ngrx ngrx-effects

我创建了以下代码,试图确保设置状态时不会再次调用 api,并避免在组件中使用订阅。

loadPackingList$ = createEffect(() => {
   return this.actions$.pipe(
     ofType(PackingPageActions.loadPackingList),
     switchMap((action) =>
         of(action).pipe(
            withLatestFrom(this.store.select(selectPackingList)),

            filter(([action, list]) => !list || list.length === 0),

            switchMap(([action, latest]) =>
               this.packingService.getPackingList(action.request).pipe(
               map((list) => PackingApiActions.loadPackingListSuccess({ list })),
               catchError((errors) =>
                   of(PackingApiActions.loadPackingListFail({ errors }))
             )
           )
         )
       )
     )
   );
});

这或多或少是有效的(API 不会再次调用),并且基于以下内容: How to send request to the server only once by using @NgRx/effects

但是,loading 属性仍然再次设置为 true,这不应该发生:

export const packingReducer = createReducer(
  initialState,
  on(PackingPageActions.loadPackingList, (state) => ({
   ...state,
   loading: true,
})),

组件的OnInit:

this.store.dispatch(
  PackingPageActions.loadPackingList({ request: this.PACKING_REQUEST })
);

有人知道如何解决这个问题吗?

谢谢!

最佳答案

首先您可以稍微清理一下流:

loadPackingList$ = createEffect(() => {
   return this.actions$.pipe(
     ofType(PackingPageActions.loadPackingList),
     withLatestFrom(this.store.select(selectPackingList)),
     filter(([action, list]) => !list || list.length === 0),
     switchMap(([action, latest]) =>
       this.packingService.getPackingList(action.request).pipe(
         map((list) => PackingApiActions.loadPackingListSuccess({ list })),
         catchError((errors) =>
           of(PackingApiActions.loadPackingListFail({ errors }))
         )
       )
     )
   );
});

不需要将外部switchMap放入of中,只是多余。

其次,您还需要对您的 reducer 进行类似的检查,以确保它不会被设置,除非效果真正生效:

export const packingReducer = createReducer(
  initialState,
  on(PackingPageActions.loadPackingList, (state) => ({
   ...state,
   loading: !state.whatever.the.path.to.the.list.is?.length,
})),

或者您可以使用已获取的列表来模拟响应,而不是进行过滤:

loadPackingList$ = createEffect(() => {
   return this.actions$.pipe(
     ofType(PackingPageActions.loadPackingList),
     withLatestFrom(this.store.select(selectPackingList)),
     switchMap(([action, latest]) =>
       ((latest && latest.length) ? of(latest) : this.packingService.getPackingList(action.request)).pipe(
         map((list) => PackingApiActions.loadPackingListSuccess({ list })),
         catchError((errors) =>
           of(PackingApiActions.loadPackingListFail({ errors }))
         )
       )
     )
   );
});

您可以通过其他方式执行此操作,例如在其中使用另一个操作来指示请求实际上正在发出,例如 loadPackingListRequest 请求,该效果将在请求之前发出以指示它实际上正在发生,这就是将 loading 状态设置为 true 的原因,这种方式可能更干净,因为您在 reducer 和效果之间没有同步代码的隐藏依赖。但这是目前的偏好。

编辑:

第三个行动策略看起来有点像这样:

loadPackingList$ = createEffect(() => {
   return this.actions$.pipe(
     ofType(PackingPageActions.loadPackingList),
     withLatestFrom(this.store.select(selectPackingList)),
     filter(([action, list]) => !list || list.length === 0),
     switchMap(([action, latest]) => from([
       of(PackingApiActions.loadingPackingList()),
       this.packingService.getPackingList(action.request).pipe(
         map((list) => PackingApiActions.loadPackingListSuccess({ list })),
         catchError((errors) =>
           of(PackingApiActions.loadPackingListFail({ errors }))
         )
       )
     ]).pipe(mergeAll()))
   );
});

这样,您的效果将发出两个操作,一个指示它实际上正在执行加载,另一个指示它是失败还是成功。

然后修改reducer以查看加载操作,而不是将loading设置为true:

export const packingReducer = createReducer(
  initialState,
  on(PackingApiActions.loadingPackingList, (state) => ({
   ...state,
   loading: true,
})),

关于Angular NGRX : Use withLatestFrom to call api only once. 但是, 'loader' 仍然设置为 true,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69886854/

相关文章:

angular - typescript angular2.d.ts错误 "Expecting new line or semicolon"

node.js - Angular8 Node js 和 npm 安装问题

javascript - Angular - 每 30 秒调用一次函数,但考虑运行该函数所需的时间

javascript - 如何从方法创建 rxjs observable

javascript - 是否应该在生产版本中删除 NGXS NgxsLoggerPluginModule?

node.js - 我在 Angular 2 的 npm install 上遇到问题

javascript - Chai ,无法测试 html 元素

具有混合数据源的 Angular 模板

angular - 使用 ngrx 时在分派(dispatch)完成后执行代码

angular - 使用@ngrx/effects 调度多个 Action ,同时确保它们按顺序执行