Как правильно отписываться от подписок в Angular?

В Angular, подписки используются для работы с асинхронными операциями, такими как HTTP-запросы, обработка событий и потоков данных. Важно правильно управлять подписками, чтобы избежать утечек памяти и неожиданного поведения в приложении.

Отписываться от подписок можно различными способами, в зависимости от того, какие функции и методы использовались для подписки. Ниже я приведу несколько распространенных случаев и способов правильного отписывания.

1. Подписка на Observable:
Когда вы используете subscribe() для подписки на Observable, возвращается объект Subscription. Чтобы отписаться от подписки, вам нужно вызвать метод unsubscribe() у этого объекта. Для этого вы можете сохранить ссылку на подписку и вызвать unsubscribe() при необходимости. Например:

import { Subscription } from 'rxjs';

private subscription: Subscription;

ngOnInit() {
  this.subscription = this.myService.getData().subscribe(
    data => {
      // логика обработки данных
    },
    error => {
      // обработка ошибок
    }
  );
}

ngOnDestroy() {
  this.subscription.unsubscribe();
}

2. Подписка на EventEmitter:
Если вы используете EventEmitter для подписки на события, вам необходимо вызвать метод unsubscribe() у самого объекта EventEmitter. Например:

import { EventEmitter } from '@angular/core';

private emitter: EventEmitter<any>;

ngOnInit() {
  this.emitter = this.myService.onDataLoaded.subscribe(
    data => {
      // логика обработки данных
    },
    error => {
      // обработка ошибок
    }
  );
}

ngOnDestroy() {
  this.emitter.unsubscribe();
}

3. Подписка на ActivatedRoute.params:
При использовании ActivatedRoute для получения параметров маршрута, вы можете воспользоваться методом takeUntil() из RxJS для автоматической отписки от подписки при разрушении компонента. Например:

import { ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

private destroy$ = new Subject();

constructor(private route: ActivatedRoute) {}

ngOnInit() {
  this.route.params.pipe(
    takeUntil(this.destroy$)
  ).subscribe(params => {
    // логика обработки параметров маршрута
  });
}

ngOnDestroy() {
  this.destroy$.next();
  this.destroy$.complete();
}

Важно заметить, что takeUntil() использует Subject для отслеживания момента разрушения компонента. При вызове next() у Subject подписка будет автоматически отписана.