Angular 생태계
RxJS 활용

takeUntilDestroyed로 구독 해제하기

팁: 이 문서는 컴포넌트와 디렉티브의 라이프사이클을 알고 있다고 가정합니다.

@angular/core/rxjs-interop의 takeUntilDestroyed 연산자를 사용하면 컴포넌트나 디렉티브가 종료될 때 옵저버블 구독을 간결하고 안정적으로 자동 해제할 수 있습니다. 이를 통해 RxJS 구독에서 자주 발생하는 메모리 누수를 방지할 수 있습니다. RxJS의 takeUntil 연산자와 비슷하게 동작하지만 별도의 Subject가 필요하지 않습니다.

import {Component, inject} from '@angular/core';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {Observable} from 'rxjs';
import {NotificationDispatcher, CustomPopupShower} from './some-shared-project-code';

@Component(/* ... */)
export class UserProfile {
  private dispatcher = inject(NotificationDispatcher);
  private popup = inject(CustomPopupShower);

  constructor() {
    // 'notifications' Observable의 이 구독은 'UserProfile' 컴포넌트가
    // 종료될 때 자동으로 해제됩니다.
    const messages: Observable<string> = this.dispatcher.notifications;
    messages.pipe(takeUntilDestroyed()).subscribe((message) => {
      this.popup.show(message);
    });
  }
}

takeUntilDestroyed 연산자는 선택적으로 DestroyRef 인자를 하나 받습니다. 이 연산자는 DestroyRef를 사용해서 컴포넌트나 디렉티브가 종료된 시점을 알아냅니다. 일반적으로 컴포넌트나 디렉티브의 생성자와 같은 의존성 주입 컨텍스트에서 takeUntilDestroyed를 호출한다면 이 인자를 생략할 수 있습니다. 의존성 주입 컨텍스트 밖에서 takeUntilDestroyed를 호출할 수 있는 코드라면 항상 DestroyRef를 전달하세요.

@Component(/* ... */)
export class UserProfile {
  private dispatcher = inject(NotificationDispatcher);
  private popup = inject(CustomPopupShower);
  private destroyRef = inject(DestroyRef);

  startListeningToNotifications() {
    // 의존성 주입 컨텍스트 밖에서 `takeUntilDestroyed`를 호출한다면
    // 항상 `DestroyRef`를 전달하세요.
    const messages: Observable<string> = this.dispatcher.notifications;
    messages.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((message) => {
      this.popup.show(message);
    });
  }
}