【问题标题】:How can I give an RxJS observable pipe access to the original observable's emission AND the pipe's previous emission?如何让 RxJS 可观察管道访问原始可观察发射和管道的先前发射?
【发布时间】:2018-11-10 02:58:16
【问题描述】:

我有一个 RxJS Observable,它对底层数据结构发出一系列更改 - 具体来说,snapshotChanges() from an AngularFirestoreCollection

  • 我目前正在将其映射到纯 JavaScript 对象数组以供我的应用使用。
  • 此数组不受任何保护,使用代码可能会意外修改此结构。
  • 只要底层数据源发出,整个数组就会重新构建,即使数组中只有一个(或有时没有)项实际发生了变化。
  • 因此,所有引用每次都会更改,这使得更改检测变得比需要的更难,并且确实降低了我的应用程序的速度。

我想做的是使用Immer 来维护一个不可变的结构,以便在结构上与“新”数组共享未更改的数据。

我无法解决的是如何将pipe() 关闭snapshotChanges() observable,以便管道可以访问先前发出的不可变数据(或首次默认值)除了 最新的snapshotChanges() 输出。

在代码中,我基本上已经拥有的是这样的:

const docToObject = (doc) => { /* change document to fresh plain object every time */ };
const mappedData$ = snapshotChanges().pipe(
    map(changes => changes.map(change => docToObject(change.payload.doc)),
    tap(array => console.log('mutable array:', array)),
);

我基本上是在寻找类似的东西,我不知道XXX(...) 应该是什么:

const newImmutableObject = (changes, old) => {
  // new immutable structure from old one + changes, structurally sharing as much as
  // possible
};
const mappedData$ = snapshotChanges().pipe(

// ==================================================================================
    XXX(...), // missing ingredient to combine snapshotChanges and previously emitted
              // value, or default to []
// ==================================================================================

    map(([snapshotChanges, prevImmutableOutput]) => newImmutableOutput(...)),
    tap(array => console.log('IMMUTABLE ARRAY with shared structure:', array)),
);

我觉得the expand operator 接近我的需要,但它似乎只在后续运行中传递先前发出的值,而我还需要新发出的snapshotChanges

给定一个 RxJS 的 Observable 管道,我怎样才能操作这个 Observable 的发射,同时还可以访问管道之前的发射?

【问题讨论】:

  • scan 似乎就是您要找的东西:snapshotChanges().pipe(scan((prev, changes) => newImmutableObject(changes, prev), []))
  • 谢谢你——这正是我要找的(我是如此接近!)。 The learn-rxjs page for scan 甚至说“你可以使用扫描创建 Redux 类似的状态管理!” Example 2: Accumulating an object 几乎准确地显示了我想要实现的目标。

标签: angular rxjs angularfire2 rxjs-pipeable-operators immer.js


【解决方案1】:

根据您的要求,我建议使用scan 运算符,它可以跟踪所有以前的状态和新状态。

const newImmutableObject = (changes, old) => {
  // new immutable structure from old one + changes, structurally sharing as much as
  // possible
};
 const mappedData$ = snapshotChanges().pipe(
 scan((acc, current) => [...acc, current], []), //<-- scan is used here
 map(([snapshotChanges, prevImmutableOutput]) => newImmutableOutput(...)),
    tap(array => console.log('IMMUTABLE ARRAY with shared structure:', array)),
);

【讨论】:

  • 谢谢。事实上,有了scan 运算符,我实际上根本不需要后续的map 运算符。
猜你喜欢
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-10
  • 1970-01-01
  • 1970-01-01
  • 2020-07-27
  • 2019-08-21
相关资源
最近更新 更多