这是我的代码
//服务方法
private cartObs$: BehaviorSubject<CartItem[]> = new BehaviorSubject(null);
getCartItems(): Observable<CartItem[]> {
return this.cartObs$.asObservable();
}
//组件中的方法
sum$: Observable<number>;
this.sum$ = this.cartService
.getCartItems()
.pipe(map((cart) =>
cart.reduce((total, item) => total + item.qty, 0)));
我需要计算 rxjs 中的数量总和。如果 observable 为空,则会出错 如何用空列表计算 rxjs 中的总和
我正在关注与此类似的arrayof obervable sum
提前致谢
错误
ERROR TypeError: Cannot read property 'reduce' of null
at MapSubscriber.eval [as project] (https://cddm0ddd.ddd.app/src/app/components/header/header.component.ts:17:50)
at MapSubscriber._next (https://cugm0.csb.app/node_modules/rxjs/_esm5/internal/operators/map.js:47:29)
at MapSubscriber.Subscriber.next (https://cugm0.csb.app/node_modules/rxjs/_esm5/internal/Subscriber.js:73:12)
at BehaviorSubject._subscribe (https://cugm0.csb.app/node_modules/rxjs/_esm5/internal/BehaviorSubject.js:34:18)
at BehaviorSubje
答案 0 :(得分:1)
我假设您的 this.cartObs$
是 BehaviorSubject 类型,默认情况下它需要设置默认值。所以我认为您将默认值设置为 null 而不是空数组,或者您将 null 发送到您的主题。
所以我在这里看到两个选项:
设置为空数组 private cartObs$: BehaviorSubject<CartItem[]> = new BehaviorSubject([]);
第二次修复reducer,以便它可以处理空值(我认为这是最安全的方法,因为那时您不在乎是否有人会将空值推入您的主题)
this.sum$ = this.cartService
.getCartItems()
.pipe(map((cart) => cart ?
cart.reduce((total, item) => total + item.qty, 0)) : 0);
cart ? cart.reduce((total, item) => total + item.qty, 0)) : 0
这意味着如果购物车不为空运行减少其空返回 0
答案 1 :(得分:1)
尽管解决方案@VovaBilyachat 解决了该问题,但在某些边缘情况下,它可能会表现出错误行为。
考虑以下内容
1.默认值空数组
在这种情况下,BehaviorSubject
被初始化为一个空数组作为默认值。
private cartObs$: BehaviorSubject<CartItem[]> = new BehaviorSubject([]);
在这种情况下,如果某个组件会像 null
一样将 undefined
或 cartObs$.next(null)
推送到它,您会得到与问题相同的错误。
2.检查值是否在 map
虽然这会是解决方案 1 中的问题,但它仍将总和返回为 0
,而输入数组是 null
或 undefined
。 sum$
observable 的使用 PoV 可能不会出现这种情况。
为了解决这些问题,您可以在 sum$
observable 中使用 filter
运算符,以便仅在定义时使用 cartObs$
排放。
this.sum$ = this.cartService.getCartItems().pipe(
filter(cart => (!!cart && !!(cart.length))),
map((cart: any) => cart.reduce((total, item) => total + item.qty, 0))
);
也就是说,如果 BehaviorSubject
的默认值没有在任何地方使用,我建议您改用 ReplaySubject
和缓冲区 1。它还会“保持”当前值并将其发送给未来的订阅者,而无需默认值。
private cartObs$: ReplaySubject<CartItem[]> = new ReplaySubject(1);