angularではRxJSでストリームを扱うことが多い。そうした中で画面遷移が絡む場合、画面遷移した後でも、前の画面で使用していたsubscribe
が生き続けるといった問題が発生する。
ということで、必要に応じて画面遷移した際に、unsubscribe
してあげる必要がある。
OnDestroy時にunsubscribeする方法
unsubscribe
する方法として、まずコンポーネントをOnDestroy
する際に、unsubscribe
する方法がある。
RxJSのSubscription#unsubscribe
を使う。
http://reactivex.io/rxjs/class/es6/Subscription.js~Subscription.html
実装すると以下のようになる。
...
// 必要に応じて以下をインポートする
import { Subscription } from 'rxjs';
...
export class App implements OnInit, OnDestroy {
eventStream$: Observable<EventStream>
subscription: Subscription;
ngOnInit() {
this.subscription = this.eventStream$.subscribe(...);
}
ngOnDestroy() {
// コンポーネントを破棄する時にunsubscribeする
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}
subscribe
するストリームが複数ある場合は、subscription
を配列にしても良い。
...
export class App implements OnInit, OnDestroy {
eventStream1$: Observable<EventStream>
eventStream2$: Observable<EventStream>
subscriptions: Subscription[] = [];
ngOnInit() {
this.subscriptions.push(this.eventStream1$.subscribe(...));
this.subscriptions.push(this.eventStream2$.subscribe(...));
}
ngOnDestroy() {
if (this.subscriptions) {
this.subscriptions.forEach(sub => sub.unsubscribe());
}
}
}
URLを基準にイベントをフィルタリングする方法
こちらは、unsubscribe
する代わりに、特定のURLの時だけsubscribe
する方法。
RxJSのfilter
オペレータを使う。
http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-filter
実装すると以下のようになる。
...
// 必要に応じて以下をインポートする
import { Router } from '@angular/router';
import 'rxjs/add/operator/filter';
...
export class App implements OnInit {
eventStream$: Observable<EventStream>
constructor(
private router: Router,
) { }
ngOnInit() {
this.eventStream$
// URLが'/app'の時だけsubscribeする
.filter((eventStream: EventStream) => this.router.url === '/app')
.subscribe(...);
}
}
subscribeするのは1回だけで良い場合
unsubscribe
で停止しても良いが、RxJSのtake
オペレータを使っても良い。
http://reactivex.io/documentation/operators/take.html
実装すると以下のようになる。
...
// 必要に応じて以下をインポートする
import 'rxjs/add/operator/take';
...
export class App implements OnInit, OnDestroy {
eventStream$: Observable<EventStream>
ngOnInit() {
this.eventStream$.take(1).subscribe(...);
}
}
まとめ
状況に応じて使い分ける。ブラウザの戻る、進むによってsubscribe
が重複したりするので、その辺りは十分に注意する。