微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决ngrx 效果进入无限循环的问题

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

enter image description here

代码如下:

home.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。这使我的代码不断分派动作,导致无限循环。我以这种方式更改了我的代码:

home.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;
  })
);

home.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),);

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

这是我的建议。享受!

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。