如何在selector中同步使用另一selector的值且不丢失同步性
问题分析
原代码的实现存在两个明显缺陷:
- 通过单独订阅
getBirthDate存到实例变量this.date的方式不可靠,异步时序问题会导致调用接口时birthDate还未完成赋值 - 实例变量无法响应
birthDate的后续更新,两个selector的值无法保持同步更新
解决方案
你要的效果完全可以用combineLatest实现,之前调用失败大概率是放置位置不对,或者没有处理流的首次发射规则(combineLatest要求所有关联流至少发射过一次值才会触发回调)。
修改后的代码如下:
searchBirthTowns({ debounce, scheduler } = { debounce: 500, scheduler: asyncScheduler }) { return this.store.pipe( select(fromStore.selectBirthFormAutocompleteField), filter(field => field === 'birthCommune'), switchMap(_ => combineLatest([ // 城市输入流:保留原有防抖、去重逻辑 this.store.pipe( select(fromStore.selectBirthFormAutocompleteData), map(x => x.seized), filter(x => !!x), debounceTime(debounce, scheduler), distinctUntilChanged() ), // 出生日期流:不需要单独订阅,由combineLatest统一管理 this.store.pipe(select(fromStore.getBirthDate)) ])), // 可选:确保两个参数都非空时才发起请求,根据业务逻辑调整 filter(([city, birthDate]) => !!city && !!birthDate), switchMap(([city, birthDate]) => this.nomenclatureService.listBirthTowns({ label: city, birthDate }) ) ); }
优化说明
- 完全移除了外部实例变量和独立订阅,从根源避免异步时序问题
- 任意一个selector的值更新时都会自动触发接口请求,天然保证两个参数完全同步
- 所有流通过
switchMap自动管理生命周期,没有额外内存泄漏风险 - 如果不需要响应
birthDate的后续更新,只需要取第一次的有效值,给出生日期流加个first()操作符即可,不需要把Observable传到service层做额外处理
如果你的业务场景允许birthDate为空,可给出生日期流加startWith(默认值)保证combineLatest能正常触发首次回调。
内容的提问来源于stack exchange,提问作者Brice Faller
相关产品推荐
相关产品推荐

