首页 > 解决方案 > ngrx 效应进入无限循环的问题

问题描述

我知道这已经被问过很多次了,但我仍然无法理解我的代码出了什么问题。似乎我的效果已经服用了类固醇,并且根本没有停止无休止地运行。我在 ngrx/store 和 ngrx/effects 版本 10.1.1

在此处输入图像描述

下面是代码:

主页.effects.ts

  public defaultState: DeployedInstanceModel;

  @Effect()
  loadDeployedInstanceData$ = this.actions$
    .pipe(
      
      ofType(DeployedInstancesTypes.GET_TABLE_DATA),
      
      mergeMap(() => {
        // reset default state before api call is made
        this.defaultState = {
          data: {}
        };
        return this.analyticsService.getDeployedInstanceData().pipe(
            map(result => {
                this.defaultState.data = result;
                console.log('[deployed-instance] the result of api call is -> ', result);
                return new DeployedInstanceGetData.GetDeployedInstanceAction(this.defaultState);
            }),
            catchError(err => {
              let errObj = {err: '', url: ''}
              errObj.err = err.statusText;
              errObj.url = err.url;
              console.log('API failure detected on the url -> ', errObj.url);
              this.showErrorPopup();
              return errObj.err;
            })
        );
      })
    )

  constructor(
    private actions$: Actions,
    private analyticsService: AnalyticsService
  ) { }

这就是我尝试从家庭组件调度我的操作的方式

home.component.ts

ngOnInit(){

    this.state = { data: {}};

    // first dispatch empty state on page load
    this.store.dispatch(new DeployedInstanceGetData.GetDeployedInstanceAction(this.state));
    
    // get the data from the store once api has been called from effects
    this.homeDeployedInstanceStore$ = this.store.select('deployedInstanceModel').subscribe(state => {
      this.totalData = state.data;
      if(Object.keys(this.totalData).length > 0){
          console.log(this.totalData);
          this.loader.stop();
      }else{
        this.loader.start();
      }
      console.log('[Deployed Instance] state from component -> ', this.totalData);
    });
}

我尝试了什么:

我尝试了下面提到的所有解决方案:

@Effect({dispatch:false})- 这里的数据被提取一次,但是this.store.select当我有返回的数据在主页上显示的空数据时我没有被再次调用

take(1)- 尝试使用此解决方案,但当用户导航出页面并再次返回同一页面时,我无法第二次调用 api。

尝试删除@Effect但又遇到了同样的问题。

如果有人能指出我正确的方向,那将非常有帮助。

标签: angularngrxngrx-storengrx-effects

解决方案


我的建议是为每个异步请求的解析创建 3 个操作。示例:FetchData、FetchDataSuccess、FetchDataFailure。但!如果要处理 catchError 中的操作,则需要发出新的 observable。

我的项目中的示例:

export const FetchDraftAction = createAction(
  '[GOALIE_TRACKER.TRACKER_DETAIL] FETCH_DRAFT',
  props<{ uuid: string }>(),
);

export const FetchDraftSuccessAction = createAction(
  '[GOALIE_TRACKER.TRACKER_DETAIL] FETCH_DRAFT_SUCCESS',
  props<{ draft: DraftRecord }>(),
);

export const FetchDraftFailureAction = createAction(
  '[GOALIE_TRACKER.TRACKER_DETAIL] FETCH_DRAFT_FAILURE',
);

并且这样做有效:

  public fetchDraft$ = createEffect(() =>
    this.actions$.pipe(
      ofType(FetchDraftAction),
      switchMap(({ uuid }) =>
        this.matchStatService.getDraftByKey(uuid).pipe(
          map(draft => FetchDraftSuccessAction({ draft })),
          catchError(() => of(FetchDraftFailureAction())),
        ),
      ),
    ),
  );

  public fetchDraftSuccess$ = createEffect(() =>
    this.actions$.pipe(
      ofType(FetchDraftSuccessAction),
      switchMap(() => [StopLoadingMessageAction()]),
    ),
  );
  public fetchDraftFailure$ = createEffect(() =>
    this.actions$.pipe(
      ofType(FetchDraftFailureAction),
      switchMap(() => [StopLoadingMessageAction()]),
    ),
  );

如您所见,catchError(() => of(FetchDraftFailureAction())),fetchDraft$. 它从of(...)操作员开始。那是因为您的效果会因错误而中断流,您需要使用新操作再次“启动”它。

这是我的建议。享受!

PS:我正在使用动作和效果创建器,但方法是相同的。


推荐阅读