如何在Angular中当NgRx状态已有数据时终止NgRx Effect
解决NgRx中重复触发HTTP请求的问题
你的核心需求是避免重复发起请求——当状态中已有数据时,再次触发RetrieveShippingContacts动作就不再执行HTTP请求;如果请求正在进行时又触发动作,要终止当前请求。原代码的问题在于没有先检查状态数据,且takeUntil的监听逻辑没有和状态判断结合起来。
以下是修正后的实现:
@Effect() fetchShippingContacts$: Observable<Action> = this.actions$ .ofType<picklistActions.RetrieveShippingContacts>(picklistActions.PicklistActionTypes.RetrieveShippingContacts) .withLatestFrom(this.store$.select(fromPicklist.getShippingContacts)) // 从store获取已有联系人数据 .switchMap(([action, existingContacts]) => { // 1. 如果已有数据,直接返回完成动作,跳过请求 if (existingContacts && existingContacts.length > 0) { return of( new picklistActions.RetrieveShippingContactsComplete(existingContacts), new applicationActions.HideLoadingAllAction() ); } // 2. 没有数据时,才发起请求,并监听下一次动作终止请求 const nextTrigger$ = this.actions$.ofType(picklistActions.PicklistActionTypes.RetrieveShippingContacts).skip(1); return this.vf.callRemoteAction([], environment.getShippingContacts.class, environment.getShippingContacts.method, true) .takeUntil(nextTrigger$) // 下一次触发动作时终止当前请求 .pipe( switchMap(response => { const parsedContacts = shippingContactsPayloadParser(response.vfResponse.payloadMap.records); return [ new picklistActions.RetrieveShippingContactsComplete(parsedContacts), new applicationActions.HideLoadingAllAction() ]; }), catchError(err => of( new applicationActions.HideLoadingAllAction() )) ); });
关键修改点说明:
- 状态前置检查:通过
withLatestFrom获取store中已有的shippingContacts,如果数据存在(非空且有长度),直接返回完成动作,完全跳过HTTP请求流程。 - 精准终止请求:只有在需要发起请求时,才创建
nextTrigger$监听下一次的RetrieveShippingContacts动作,用takeUntil终止当前未完成的请求。 - 简化操作符链:将原来嵌套的
switchMap改为pipe链式调用,逻辑更清晰;用of替代from处理同步动作返回,更符合RxJS最佳实践。
另外,确保你已经在reducer中正确维护了shippingContacts的状态,并且fromPicklist.getShippingContacts是正确的状态选择器,能准确取出对应的数据切片。
内容的提问来源于stack exchange,提问作者Naveen Sain
相关产品推荐
相关产品推荐

