繁体   English   中英

ngrx 效应进入无限循环的问题

[英]problems with ngrx effect going into infinite loop

我知道这已经被问过很多次了,但我仍然无法理解我的代码出了什么问题。 似乎我的效果已经服用了类固醇,并且根本没有停止无休止地运行。 我在 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 ,但我又遇到了同样的问题。

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

根据评论中提到的用户Franky238的说法,我终于能够解决这个问题:

我的代码的问题是我在效果文件中返回了相同的操作,即最初从 home.component.ts 调度的new DeployedInstanceGetData.GetDeployedInstanceAction 这使我的代码不断地调度动作,导致无限循环。 我以这种方式更改了我的代码:

主页.effects.ts

switchmap 中的代码现在如下所示。 我已更改return new DeployedInstanceGetData.GetDeployedInstanceAction(this.defaultState); return new DeployedInstanceGetData.DataFetchSuccessAction(this.defaultState);

return this.analyticsService.getDeployedInstanceData().pipe(
  map(result => {
    this.defaultState.data = result.data;
    console.log('[deployed-instance] the result of api call is -> ', this.defaultState.data);
    return new DeployedInstanceGetData.DataFetchSuccessAction(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;
  })
);

主页.actions.ts

export const GET_DEPLOYEMENT_DATA = DeployedInstancesTypes.GET_TABLE_DATA;
export const DEPLOYEMENT_DATA_FETCH_SUCCESS = DeployedInstancesTypes.TABLE_FETCH_SUCCESS;

export class GetDeployedInstanceAction implements Action{
  readonly type = GET_DEPLOYEMENT_DATA;
  constructor(public payload: DeployedInstanceModel) {
    console.log('[result] action with payload =>', payload);
  }
}

// added this new action to accommodate new effect and 
// save data in the store below.

export class DataFetchSuccessAction implements Action{
  readonly type = DEPLOYEMENT_DATA_FETCH_SUCCESS;
  constructor(public payload: DeployedInstanceModel) {
    console.log('[result] action dispatch from effects success =>', payload);
  }
}

export type Actions = GetDeployedInstanceAction | DataFetchSuccessAction

我的建议是为每个异步请求的解析创建 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()]),
    ),
  );

如您所见,在fetchDraft$中有catchError(() => of(FetchDraftFailureAction())), 它以of(...)运算符开头。 那是因为您的效果会在出错时破坏 stream 并且您需要使用新操作再次“启动”它。

这是我的建议。 享受!

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

暂无
暂无

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

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