如何解决ngrx 效果进入无限循环的问题
我知道这之前已经被问过很多次了,但我仍然无法理解我的代码出了什么问题。似乎我的效果已经消耗了类固醇,并且根本不会停止无休止地运行。我在 ngrx/store 和 ngrx/effects 版本 10.1.1
代码如下:
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 举报,一经查实,本站将立刻删除。