[英]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.