NgRx场景:无数据时派发动作后需重新查询Store
问题根源
当前代码的核心问题是:当Store查询返回undefined时,虽然触发了数据加载的action,但后续Store中数据更新后,现有订阅逻辑无法正确捕获到新的查询结果——本质是单次的subscribe没有处理“触发加载后重新监听Store数据更新”的流程,或者selector没有在数据更新时重新发射值。
修复方案
我们可以通过RxJS的操作符优化逻辑,确保无数据时触发加载动作,并自动等待数据加载完成后重新获取Store中的有效数据,同时避免重复请求。
基础修复版本
this.subscriptions.add( this.store .select(fromSharedStore.getIbmerEntityByQuery({ q })) .pipe( debounceTime(250), switchMap(x => { if (x) { // 已有有效数据,直接返回 return of(x); } else { // 无数据时派发加载动作,然后监听Store直到获取到有效数据 this.store.dispatch(fromSharedStore.SearchIbmers({ search: { q } })); return this.store.select(fromSharedStore.getIbmerEntityByQuery({ q })).pipe( filter(res => res !== undefined), take(1) ); } }), // 过滤掉无效的undefined值,确保订阅只处理有效数据 filter(x => x !== undefined) ) .subscribe(x => { this.flatChildren = x.map(v => ({ ...v, name: v.cn ? v.cn[0] : '', email: v.emailaddress ? v.emailaddress[0] : '', short_name: v.cn[0], parent: 'Author', search_id: v.cn[0], })); this.searching = false; this.loaded = true; this.changeDetectorRef.markForCheck(); }) );
优化防重复请求版本
如果需要避免重复派发相同的加载动作,可以结合Store中的加载状态selector(假设已存在):
import { combineLatest, EMPTY } from 'rxjs'; import { filter, switchMap, take } from 'rxjs/operators'; // ... this.subscriptions.add( combineLatest([ this.store.select(fromSharedStore.getIbmerEntityByQuery({ q })), this.store.select(fromSharedStore.getIsIbmerSearchLoading()) // 假设的加载状态selector ]).pipe( debounceTime(250), switchMap(([data, isLoading]) => { if (data) { return of(data); } else if (!isLoading) { // 仅当未在加载时才派发动作 this.store.dispatch(fromSharedStore.SearchIbmers({ search: { q } })); return this.store.select(fromSharedStore.getIbmerEntityByQuery({ q })).pipe( filter(res => res !== undefined), take(1) ); } // 正在加载时返回空流,跳过处理 return EMPTY; }), filter(x => x !== undefined) ) .subscribe(x => { this.flatChildren = x.map(v => ({ ...v, name: v.cn ? v.cn[0] : '', email: v.emailaddress ? v.emailaddress[0] : '', short_name: v.cn[0], parent: 'Author', search_id: v.cn[0], })); this.searching = false; this.loaded = true; this.changeDetectorRef.markForCheck(); }) );
关键修改点说明
- 使用
switchMap接管无数据场景的处理:触发加载动作后,重新订阅Store的查询结果,直到获取到有效数据 filter操作符过滤undefined值,确保订阅回调只处理有效数据take(1)确保在获取到第一次有效数据后停止监听,避免重复处理- 结合加载状态的版本通过
combineLatest避免重复派发加载动作,防止多次发起相同请求
内容的提问来源于stack exchange,提问作者Mohamed Ibrahim
相关产品推荐
相关产品推荐

