Angular

【Angular】unsubscribe()の方法

マナビト
マナビト
こんにちはマナビトです。
普段はフロントエンドエンジニアとしてJavaScript/TypeScript/Aangular/GraphQLを
メインに開発業務を行なっています。

AngularのRxJSを使用している方であれば「unsubscribe()しましょう」という話は必ず耳にしたことがあるかと思います。何故なら受け取ったObservableの値を停止するためにunsubscribe()しなかった場合、ページを移動(コンポーネントが破棄)したとしてもSubscriptionだけが残り続け、無駄なリソースがsubscribe()し続けてしまうためです。
※ unsubscribe()しなかった場合の弊害は下記Qiita記事に詳しく記載されています。

今回は、Angular/RxJS歴9ヶ月が経ちunsebscribe()の方法がいくつかあるなと思い紹介したいと思います。(といっても2つですが…)

OnDestroy時にunsubscribeする

まず1点目は、割と一般的な方法かもしれませんがngOnDestroyメソッドが呼び出されたタイミングでemitされるEventEmitterを作っておき、RxJSのtakeUntilパイプでunsubscribeする実装パターンです。

import { Component, OnDestroy, OnInit, EventEmitter, Output } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { takeUntil } from 'rxjs/operators';

@Component({})
export class FormComponent implements OnDestroy {
  @Output() valueChange = new EventEmitter<any>();
  private readonly onDestroy$ = new EventEmitter();

  readonly form = new FormGroup({
    name: new FormControl(),
  });

  ngOnDestroy() {
    this.onDestroy$.emit();
  }

  constructor() {
    this.form.valueChanges
     .pipe(takeUntil(this.onDestroy$),)
     .subscribe(value => {
        this.valueChange.emit(value);  
   //ここに処理を記載する。
   //コンポーネントが破棄されると同時に、破棄されるので、unsubscribeメソッドが不要。
      });
  }

  ngOnInit() {}
}

TakeUntilはストリームAにデータが流れるまで、このストリームBにデータを流すかを決めるためのオペレーターです。TakeUntilに引数に別のストリームを指定することでソースのObservableの値を停止して、takeUntil出力のObservableを流すことができます。
引数にngOnDestroyを指定すると、unsubscribeメソッドを呼び出さず、Observableを停止することが可能です。

@ngneat/until-destroyを使用する

「@ngneat/until-destroy」はコンポーネントが破棄されたタイミングでobservableをunsubscribeしてくれる比較的新しいライブラリです。

まずはnpmやyarnでライブラリをインストールします。

npm install @ngneat/until-destroy

# Or if you use yarn
yarn add @ngneat/until-destroy

@ngneat/until-destroyをインポートして@UntilDestroy()デコレータを宣言することで使用することができます。

import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';

@UntilDestroy()
@Component({})
export class InboxComponent {
  ngOnInit() {
    interval(1000).pipe(untilDestroyed(this)).subscribe();
  }
}

単純にunsubscribeするだけでなく、blackListプロパティを使用してunsebscribeしたいプロパティを名前をつけて選択することが出来ます。

@untilDestroy({ checkProperties: true, blackList: ['subscription1'] })
@component({})
export class HomeComponent {

 // blackListで指定したsubscription1はunsubscribedされない。
  subscription1: Subscription;

  // subscription2はunsubscribedされる。
  subscription2: Subscription;
}

arrayNameプロパティの使用やRxJSのEventfromオペレータを使用してeventがトリガーされたタイミングでunsebscribeを実行するなど、様々なシュチュエーションに合わせて使用することができかなり便利かなっと思います。

今回はここまでとなります。