【Angular】unsubscribeの重要性【RxJS】

ANGULAR

みなさんこんにちは、現役エンジニアのサメハックです

未経験からWebエンジニアに転職し、
正社員として5年働いたのちフリーランスとして独立しました。

Angularの解説シリーズです。

今回はunsubscribeの重要性について学んでいきましょう!

駆け出しエンジニアや未経験の方、
また新入社員を指導する先輩社員にとっても
わかりやすいように解説していきます!

この記事を読むと・・・
  • unsubscribeの重要性がわかる

※PCにnpm、nodeがインストールされている前提で記述します。
 yarn等をお使いの方は読み替えてください。

環境がない人はcodesansboxを使ってね!

subscribeとは

subscribeとは、Observableを購読・実行するための関数です。

例えばserviceファイルで保管したdata$というObservableを購読した場合は
以下のような処理になると思います。

this.service.data$.subscribe(
  (受け取った値) => {
    // data$が更新されると自動的にこの処理が呼ばれる
  }
)

RxJSに慣れていないと、購読という概念が理解し辛いかと思いますが、
ここでいう購読とは、ウォッチャ/監視と読み替えていただくと理解しやすいと思います。  

この場合、data$が更新されると自動的にsubscribe内の処理が実行されます。

また、今回のテーマからズレるので深く触れませんが
Observableはsubscribeすることで初めて動作します。

subscribeとは、Observableを購読(監視)する関数で
監視した値が更新されると自動で実行されるよ!

unsubscribeとは

unsubscribeとはsubscribeで設定した購読を停止する処理です。

Angularを触ったことがない人にとっては馴染みがないと思いますが、
subscribeで購読した設定は自動では解除されず、
特にSPAではページ遷移しようがコンポーネントが破棄されようが
ずーーーっと値を監視し、処理が実行されてしまいメモリリークの原因となります。

subscribeとunsubscribeは必ずセットで使う必要があります。

unsubscribeとは購読を停止する処理だよ!
subscribeとunsubscribeは必ずセットで使うよ!

購読停止(unsubscribe)するための前提知識

前提知識として以下の2点を抑えておく必要があります。

・Observable.subscribe()はSubscriptionオブジェクトを返す
・Subscriptionオブジェクトはunsubscribe関数を持っており、
 これを実行することでObservableの購読停止ができます

Subscriptionオブジェクトを管理することで、初めて購読停止処理ができるよ!

unsubscribeする構文1

const subscription = this.service.data$.subscribe(
  (受け取った値) => {
    // data$が更新されると自動的にこの処理が呼ばれる
  }
)

// 購読の停止
subscribe.unsubscribe();
subscribe()の戻り値を受け取る構文だよ!

unsubscribeする構文2※オススメ

// 購読設定停止用
private subscriptions = new Subscription();


this.subscriptions.add(
    this.service.data$.subscribe(
        (受け取った値) => {
            // data$が更新されると自動的にこの処理が呼ばれる
        }
    )
);


/**購読を停止 */
this.subscriptions.unsubscribe();
購読設定をsubscriptionsにaddしてまとめて解除する方法だよ!
最も汎用性が高いので、基本的にこれを使おう!

購読を停止するタイミング

ngOnDestroy※コンポーネントが削除されたタイミング

購読を停止する最もポピュラーなタイミングはngOnDestroyです。

// 購読設定停止用
private subscriptions = new Subscription();

ngOnInit() {
  this.subscriptions.add(
    this.service.data$.subscribe(
      (受け取った値) => {
        // data$が更新されると自動的にこの処理が呼ばれる
      }
    )
  );
}

ngOnDestroy() {
  /**コンポーネントが破棄されたタイミングで購読を停止 */
  this.subscriptions.unsubscribe();
}

ngOnDestroyというのはAngularのライフサイクルで、
コンポーネントが破棄されたタイミングで実行されます。

これでコンポーネントが破棄されたタイミングで
購読の停止ができるよ!

関数内※重要

関数内で購読設定をすることはあまりないですが、
NGRXを使ったシステムではSTOREに保管したデータを
関数内で取得したいケースが出てきます。

myFunc() {  
  /* 処理1 */
  this.store.select(selectData).subscribe(
      (受け取った値) => {
   // selectDataの対象が更新されると自動的にこの処理が呼ばれる    } );
/* 処理2 */ }

このような関数が存在した場合、一度myFunc()を実行すると

this.store.select(selectData).subscribe( /*略*/ );

上記の処理は関数が終了しても生き続けてしまい、
selectDataの対象が更新されると突然subscribe()の処理だけが実行されてしまいます。

このように意図しない動作が起こりうるので、関数内でsubscribeを実行する場合には
ngOnDestroyに頼らず、関数終了時にunsubscribeを実行することが大切です。

myFunc() {  
    // 購読設定停止用
    const myFuncSubscriptions = new Subscription();
    /* 処理1 */

    myFuncSubscriptions.add(
        this.store.select(selectData).subscribe(
            (受け取った値) => {
                // selectDataの対象が更新されると自動的にこの処理が呼ばれる
            }
        );
    )

    /* 処理2 */

    // 購読の停止
    myFuncSubscriptions.unsubscribe()
}
関数内で購読設定をする場合、必ずその関数終了時に購読の停止を行おう!

まとめ

  • subscribe・・・Observableを購読(=監視)するための関数、購読対象が更新されると呼ばれる
  • unsubscribe・・・subscribeで設定した購読を停止する処理
  • subscribeとunsubscribeは必ずセットで使う
  • unsubscribeするタイミング①コンポーネントが破棄されるタイミング
  • unsubscribeするタイミング②subscribeを含む関数の終了時

満足いただけたら、1クリックなのでSNSフォローしてもらえると嬉しいです🦈

タイトルとURLをコピーしました