我正在与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不起作用。
您到底想要实现什么?如果它正在更改您列表中更新的元素,那么您应该考虑以下内容:
-
将您的列表定义为主题:
this.list$ = new Subject<ListType[]>();
-
获取当前列表和下一个列表$
this.api.getAll().subscribe(this.list$.next); // dont forget to unsubscribe or youll get a memory leak
-
观察更新:
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
-
将您的列表$与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$);
这不是最干净的解决方案,因为每次更新时都需要重新创建更新逻辑,但它仍然与以前相对接近。