如何在单次调用中合并Angular NgRx的多个store select
NgRx 合并多个 Store Select 到同一执行函数方案
combineLatest本身完全可以实现该需求,之前逻辑未正常触发通常是两个原因:
- 导入路径错误:
combineLatest需要从rxjs包根路径导入,不要从rxjs/operators路径导入旧版操作符形式的方法 - 输入流未全部发出初始值:
combineLatest的触发规则是所有传入的流都至少发出过1次值后,才会在任意流更新时触发订阅回调,如果其中一个状态切片初始化时无默认值,就会一直等待不触发。
基础实现代码
// 注意导入路径 import { combineLatest } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; constructor(private store: Store<fromStore.AppState>) {} ngOnInit(): void { // 分别定义两个状态选择流 const userInfo$ = this.store.select("userInfo", "user"); const cartDetail$ = this.store.select("cart"); // 合并流统一订阅 combineLatest([userInfo$, cartDetail$]) .pipe(takeUntil(this._unsubscribeAll)) .subscribe(([userInfo, cartDetail]) => { // 回调中可同时获取两个状态的最新值 console.log(userInfo); console.log(cartDetail); // 统一编写业务逻辑即可 }); }
初始值缺失问题修复
如果某一个状态是异步加载、初始无值,可以给对应流加startWith操作符设置兜底默认值,保证流能正常发出初始信号:
import { combineLatest } from 'rxjs'; import { takeUntil, startWith } from 'rxjs/operators'; // 省略其他重复代码 combineLatest([ userInfo$.pipe(startWith(null)), // 用户信息未加载完成时兜底为null cartDetail$.pipe(startWith([])) // 购物车未加载完成时兜底为空数组 ]) .pipe(takeUntil(this._unsubscribeAll)) .subscribe(([userInfo, cartDetail]) => { // 业务逻辑中增加对应判空即可 if (!userInfo) return; console.log(userInfo, cartDetail); })
可复用方案:封装联合选择器
如果这两个状态的组合逻辑需要在多处使用,可以直接用NgRx自带的createSelector封装成统一的选择器,不需要每次在组件里合并流:
// 在Store的selectors定义文件中编写 export const selectUserAndCart = createSelector( selectUser, // 已封装的取userInfo.user的选择器 selectCart, // 已封装的取cart状态的选择器 (userInfo, cart) => ({ userInfo, cart }) ); // 组件中直接调用即可 ngOnInit(): void { this.store.select(selectUserAndCart) .pipe(takeUntil(this._unsubscribeAll)) .subscribe(({userInfo, cart}) => { console.log(userInfo, cart); }) }
内容的提问来源于stack exchange,提问作者Johnny
相关产品推荐
相关产品推荐

