웹사이트 검색

takeUntil RxJS 연산자를 사용하여 구독을 선언적으로 관리하는 방법


소개

Angular는 HTTP 서비스에서 반환되거나 비동기 파이프를 사용할 때와 같은 관찰 가능한 구독에서 구독 취소를 처리합니다. 그러나 다른 상황에서는 모든 구독을 관리하고 오래 지속되는 구독을 취소하는 것이 빠르게 어려워질 수 있습니다. 대부분의 구독에서 구독을 취소하는 정책에도 고유한 문제가 있습니다.

이 기사에서는 수동 구독 및 구독 취소에 의존하는 예제 Angular 애플리케이션을 제공합니다. 그런 다음 구독을 선언적으로 관리하기 위해 takeUntil 연산자를 사용하는 예제 Angular 애플리케이션과 비교합니다.

전제 조건

이 기사를 따라 하려면 다음이 필요합니다.

  • RxJS 라이브러리, 특히 ObservableSubscription에 익숙하면 도움이 될 것입니다.
  • Apollo 및 GraphQL에 익숙하면 도움이 되지만 필수는 아닙니다.

이 튜토리얼은 Node v15.3.0, npm v6.14.9, @angular/core v11.0.4, rxjs v6.6.3, apollo-angular v2.1.0, graph-tag v2.11.0. 이 문서는 @angular/corerxjs의 이전 버전에서 마이그레이션할 때 변경 사항을 반영하도록 편집되었습니다.

수동으로 구독 취소

두 개의 구독에서 수동으로 구독을 취소하는 예부터 시작하겠습니다.

이 예에서 코드는 Apollo watchQuery를 구독하여 GraphQL 엔드포인트에서 데이터를 가져옵니다.

이 코드는 또한 onStartInterval 메서드가 호출될 때 구독하는 간격 관찰 가능 항목을 생성합니다.

import { Component, OnInit, OnDestroy } from '@angular/core';

import { Subscription, interval } from 'rxjs';

import { Apollo } from 'apollo-angular';
import gql from 'graphql-tag';

@Component({ ... })
export class AppComponent implements OnInit, OnDestroy {
  myQuerySubscription: Subscription;
  myIntervalSubscription: Subscription;

  constructor(private apollo: Apollo) {}

  ngOnInit() {
    this.myQuerySubscription = this.apollo.watchQuery<any>({
      query: gql`
        query getAllPosts {
          allPosts {
            title
            description
            publishedAt
          }
        }
      `
    })
    .valueChanges
    .subscribe(({data}) => {
      console.log(data);
    });
  }

  onStartInterval() {
    this.myIntervalSubscription = interval(250).subscribe(value => {
      console.log('Current value:', value);
    });
  }

  ngOnDestroy() {
    this.myQuerySubscription.unsubscribe();

    if (this.myIntervalSubscription) {
      this.myIntervalSubscription.unsubscribe();
    }
  }
}

이제 구성 요소에 유사한 구독이 많이 있다고 가정하면 구성 요소가 소멸될 때 모든 구독이 취소되도록 하는 상당한 프로세스가 빠르게 될 수 있습니다.

takeUntil을 사용하여 선언적으로 구독 취소

해결책은 takeUntil 연산자로 구독을 구성하고 ngOnDestroy 수명 주기 후크에서 진실한 값을 내보내는 주제를 사용하는 것입니다.

다음 스니펫은 똑같은 작업을 수행하지만 이번에는 코드가 선언적으로 구독을 취소합니다. 추가 혜택은 더 이상 구독에 대한 참조를 유지할 필요가 없다는 것입니다.

import { Component, OnInit, OnDestroy } from '@angular/core';

import { Subject, interval } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import { Apollo } from 'apollo-angular';
import gql from 'graphql-tag';

@Component({ ... })
export class AppComponent implements OnInit, OnDestroy {
  destroy$: Subject<boolean> = new Subject<boolean>();

  constructor(private apollo: Apollo) {}

  ngOnInit() {
    this.apollo.watchQuery<any>({
      query: gql`
        query getAllPosts {
          allPosts {
            title
            description
            publishedAt
          }
        }
      `
    })
    .valueChanges
    .pipe(takeUntil(this.destroy$))
    .subscribe(({data}) => {
      console.log(data);
    });
  }

  onStartInterval() {
    interval(250)
    .pipe(takeUntil(this.destroy$))
    .subscribe(value => {
      console.log('Current value:', value);
    });
  }

  ngOnDestroy() {
    this.destroy$.next(true);
    this.destroy$.unsubscribe();
  }
}

수동으로 구독을 취소하는 대신 takeUntil과 같은 연산자를 사용하면 Observable이 완료되고 Observable에서 완료 이벤트가 트리거됩니다.

의도하지 않은 부작용이 발생하지 않도록 코드를 확인하십시오.

결론

이 문서에서는 takeUntil을 사용하여 선언적으로 구독을 취소하는 방법에 대해 배웠습니다. 불필요한 구독을 취소하면 메모리 누수 방지에 기여합니다. 선언적으로 구독을 취소하면 구독에 대한 참조가 필요하지 않습니다.

take, takeWhilefirst와 같은 다른 유사한 RxJS 연산자가 있으며 모두 관찰 가능 항목을 완료합니다.

Angular에 대해 자세히 알아보려면 연습 및 프로그래밍 프로젝트에 대한 Angular 주제 페이지를 확인하십시오.