Rxjs扫描不会触发combineLatest



我正在与combineLatest和scan-rxjs运算符(使用Angular 8(作斗争。基本上,我显示的是一个可以过滤的列表。

因此,我有第一个可观察的list$ = this.api.getAll()
和第二个filteredList$ = combineLatest(this.list$, this.form.valueChanges())
,在我的HTML中,我使用filteredList$ | async显示filteredList$内容。这很好(意思是,表单中的任何更改都会更新我的filteredList$(

然而,最终用户能够更新列表的一个元素;当他这样做的时候,我用这种方式更新我的list$Observable:

this.api.update(listElement)
.subscribe((updatedElmt) => {
this.list$ = this.list$.pipe(
concatMap(value => of(...value)),
scan((acc, listElmt) => listElmt._id === updatedElmt._id ? [...acc, updatedElmt] : [...acc, listElmt], []),
);
});

这也很有效
但是,combineLatest不会被触发,因此,在刷新页面之前,我的UI永远不会更新。我认为这是因为list$指针没有改变,所以没有理由触发combineLatest;但我怎么能强迫它呢?

BTW,使用changeDetector检测Changes或markForCheck不起作用。

您到底想要实现什么?如果它正在更改您列表中更新的元素,那么您应该考虑以下内容:

  1. 将您的列表定义为主题:

    this.list$ = new Subject<ListType[]>();
    
  2. 获取当前列表和下一个列表$

    this.api.getAll().subscribe(this.list$.next); // dont forget to unsubscribe or youll get a memory leak
    
  3. 观察更新:

    updateList$ = this.api.update(listElement).pipe(
    withLatestFrom(this.currentList$),
    map(([updatedElement, currentList]) => {
    return currentList.map(listElement => listElement._id === udaptedElement._id ? updatedElement : listElement),
    })
    ).subscribe(this.list$.next) // dont forget to unsubscribe (takeUntil()) should work here
    
  4. 将您的列表$与valueChanges 合并

    combineLatest([this.list$, this.form.valueChanges()])).pipe(....)
    

this.list$=。。。为属性设置一个新值,但组合Latest ist订阅this.list$的旧值。这将导致内存泄漏。

this.list$ = someObservableFunc$(); // gives first Observable<any>
const observeList$ = combineLatest([this.list$, otherObservable$]); // gives combination of first Observable<any> and otherObservable$
this.list$ = anotherObservableFunc$(); // gives second Observable<any> but observeList$ keeps subscription to first Observable<any>

您可以用条件强制两者并将它们连接起来;

concat(list$, filteredList$).subscribe(function() {/*do something */});

类似问题

考虑以下代码:

let a = 1;
const b = 2;
const c = a + b;
a = 10;
console.log(c);

我相信你以前见过这种事。当然,这打印的是3(1+2(,而不是12(10+2(。所以问题";我如何在这里强制c为12"这是一个很难回答的问题。

答案可能是完全删除c。

let a = 1;
const b = 2;
a = 10;
console.log(a + b);

但是,如果您希望以后能够引用c,这并不能真正起作用。也许您可以thunk c(使其成为一个无参数函数(并调用它来获得一个惰性值。

let a = 1;
const b = 2;
const c = () => a + b;
a = 10;
console.log(c());

这类问题有很多解决方案,它们都取决于你想要实现的目标。没有银弹。


一种可能的解决方案

你使用的是RxJS,所以我认为依靠其中的一些机制来实现你的目标是合适的。

与其让list$成为一个可观察的api,为什么不以某种方式将list$订阅到可观察的api呢。当然,要做到这一点,您需要list$既是一个可观察的(价值流(,也是一个观察者。

幸运的是,RxJS附带了一些已经可以做到这一点的构造。你可以阅读一些主题,因为我会在这里使用ReplaySubject(但也许主题或行为主题更适合这份工作。这取决于你的需求(。

// list$ is an observable **and** and observer
const list$ = new ReplaySubject();
// Tell list to observe the api
this.api.getAll().subscribe(this.list$);
// Keep this as-is
filteredList$ = combineLatest(this.list$, this.form.valueChanges())
// To update
combineLatest(this.list$, this.api.update(listElement)).pipe(
take(1),
map(([list, updatedElmt]) => list.map(listElmt => 
listElmt._id === updatedElmt._id ? updatedElmt : listElmt
))
).subscribe(this.list$);

这不是最干净的解决方案,因为每次更新时都需要重新创建更新逻辑,但它仍然与以前相对接近。

最新更新