我有一个简单的组件,可以从状态中选择一些内容并侦听更改:
private items$: Observable<Item[]>;
private alive: boolean = true;
contructor(private store: Store<state>) {
this.items$ = this.store.select(selectItems);
}
ngOnInit() {
this.items$
.pipe(
takeWhile(() => this.alive)
)
.subscribe((items: Item[]) => {
console.log('items changed!', items);
// dispatch some actions
});
}
ngOnDestroy() {
this.alive = false;
}
它完美运行-每次更改项目时,我都会看到“项目已更改!”记录的字符串。当我重定向到其他地方并且组件被销毁时,订阅将无法运行。
但是当我重定向回该组件并再次激活订阅时,即使没有任何更改,它也会立即执行与开始时相同的更改。
例如,当我进入页面时:
items changed! null
items changed! ['a', 'b', 'c']
items changed! ['a', 'b', 'c', 'd']
当我重定向并返回到组件时:
items changed! ['a', 'b', 'c', 'd']
items changed! ['a', 'b', 'c', 'd']
items changed! ['a', 'b', 'c', 'd']
这是怎么了?我尝试过takeUntil
和一个主题,但是我尝试过手动退订-没有任何方法可以解决问题。
答案 0 :(得分:1)
对主题使用takeUntil
private items$: Observable<Item[]>;
private finalised = new Subject<void>();
contructor(private store: Store<state>) {
this.items$ = this.store.select(selectItems);
}
ngOnInit() {
this.items$
.pipe(
takeUntil(this.finalised)
)
.subscribe((items: Item[]) => {
console.log('items changed!', items);
// dispatch some actions
});
}
ngOnDestroy() {
this.finalised.next();
this.finalised.complete();
}
答案 1 :(得分:0)
取消订阅或takeUntil将在组件销毁后完成,并且项在销毁前已更改。
您收到3次items changed!
消息,因为在items$
中有3个下一个事件,因此订阅者被呼叫3次。
如果您要忽略对象与先前事件相同的更改事件,建议使用distinctUntilChanged
运算符。
我将看起来像这样:
items$
.pipe(distinctUntilChanged((previous, current) => previous[0] === current[0] && ...)) /*
.subscribe(items => console.log('items changed!', items));
(previous, current) => previous === current
,但是如果是字符串['a', 'b', 'c', 'd'] !== ['a', 'b', 'c', 'd']
,则必须编写比较函数。答案 2 :(得分:0)
我认为您的问题实际上是在销毁组件时您没有取消订阅。
您正在使用takeWhile
,但此操作符仅在其源发出时作出反应。这意味着设置this.alive = false;
不会执行任何操作。只有在此之后发出this.items$
时,它才能完成链。 takeWhile
会将其捕获,从而完成整个链。但这可能不会发生。
推荐的方法是使用takeUntil
或手动退订。这已经在这里讨论了很多次,这个答案应该告诉您确切要做什么:Angular/RxJs When should I unsubscribe from `Subscription`。