You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular NGRX使用withLatestFrom实现API仅调用一次但loader仍被置为true如何解决

问题根因

你遇到的问题本质是NGRX中被分发的Action会同时传递给Reducer和Effect:

  • 每次你分发PackingPageActions.loadPackingList,监听了该Action的Reducer都会第一时间执行,将loading置为true
  • 而Effect中做的过滤逻辑仅会决定是否发起API请求,不会阻止Action流向Reducer,如果你已经有缓存数据,Effect不会再触发success/failAction来重置loading,最终就会导致loading状态异常。

解决方案

方案1:修改Reducer逻辑,设loading前先判断缓存是否存在

直接在Reducer处理loadPackingList的逻辑中,先判断当前State里有没有已有的列表,有就不修改loading状态,改动量最小:

export const packingReducer = createReducer(
  initialState,
  on(PackingPageActions.loadPackingList, (state) => {
    // 已有数据的情况下不修改loading状态
    if (state.packingList?.length > 0) return state
    return {
      ...state,
      loading: true
    }
  }),
  // 其余success、fail的reducer逻辑保持不变
  on(PackingApiActions.loadPackingListSuccess, (state, {list}) => ({
    ...state,
    loading: false,
    packingList: list
  })),
  on(PackingApiActions.loadPackingListFail, (state) => ({
    ...state,
    loading: false
  }))
)

方案2:拆分Action,职责分离更规范

你可以把原来的Action拆成两个,逻辑边界更清晰,后续扩展更方便:

  1. 组件触发的PackingPageActions.requestPackingList:仅用于通知Effect判断是否需要加载,Reducer不监听这个Action
  2. 真正触发加载的PackingPageActions.startLoadingPackingList:Effect判断需要发起请求时分发,Reducer监听这个Action来设置loading为true

修改后的Effect代码:

import { EMPTY, concat } from 'rxjs';

loadPackingList$ = createEffect(() => {
  return this.actions$.pipe(
    ofType(PackingPageActions.requestPackingList),
    switchMap((action) =>
      of(action).pipe(
        withLatestFrom(this.store.select(selectPackingList)),
        switchMap(([action, list]) => {
          // 已有数据直接终止流
          if (list?.length > 0) return EMPTY
          // 先分发开始加载的Action,再发起API请求
          return concat(
            of(PackingPageActions.startLoadingPackingList()),
            this.packingService.getPackingList(action.request).pipe(
              map((list) => PackingApiActions.loadPackingListSuccess({ list })),
              catchError((errors) =>
                of(PackingApiActions.loadPackingListFail({ errors }))
              )
            )
          )
        })
      )
    )
  );
});

修改后的Reducer代码:

export const packingReducer = createReducer(
  initialState,
  // 仅监听startLoading的Action来设置loading
  on(PackingPageActions.startLoadingPackingList, (state) => ({
    ...state,
    loading: true
  })),
  // 其余success、fail逻辑保持不变
)

内容的提问来源于stack exchange,提问作者Robin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 10:54:03