角度观察列表中的总和

时间:2021-04-22 05:39:56

标签: angular typescript rxjs

这是我的代码

//服务方法

 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

2 个答案:

答案 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 一样将 undefinedcartObs$.next(null) 推送到它,您会得到与问题相同的错误。

2.检查值是否在 map

中定义

虽然这会是解决方案 1 中的问题,但它仍将总和返回为 0,而输入数组是 nullundefinedsum$ 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);