Як DestroyRef полегшив розробку за допомогою Angular 16
Як DestroyRef полегшив розробку за допомогою Angular 16

Як DestroyRef полегшив розробку за допомогою Angular 16

Front-end 10.06.2023 2 min read

З DestroyRef більше не потрібно використовувати хук життєвого циклу ngOnDestroy для скасування підписки.

Ми чудово знаємо про необхідність завершення підписки, коли компонент знищується, інакше ми призведемо до витоку пам’яті, і наша програма/браузер/машина клієнта ставатиме все повільнішою через велику кількість сміття в пам’яті.

До того, як Observable Pattern додали до Angular 16, використовувалось безліч різних технік:

  • Використання екземпляра Subscription — необхідно було оголосити новий екземпляр Subscription, присвоїти йому підписку і викликати його метод unsubscribe, коли компонент буде знищено. Цей підхід мав свої обмеження, оскільки вам доведеться оголошувати окремі змінні для кожної підписки, як показано в прикладі нижче:
export class DemoComponent implements OnInit, OnDestroy {

  subscription: Subscription = new Subscription();

  ngOnInit(): void {
    this.subscription = of([]).subscribe();
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }
}
  • Використання масиву підписок — у цьому сценарії ми можемо використовувати скільки завгодно підписок та оперувати ними за допомогою одної змінної. Але якщо ви думаєте про чистий код і читабельність, це теж не здається ідеальним варіантом, оскільки наш код уже обернуто методом push array. З простим прикладом, наведеним нижче, це не здається проблемою, але просто уявіть кілька складніших операцій над кількома потоками:
export class DemoComponent implements OnInit, OnDestroy {

  subscriptions: Subscription[] = [];

  ngOnInit(): void {
    this.subscriptions.push(of([]).subscribe());
  }

  ngOnDestroy(): void {
    this.subscriptions
      .forEach((subscription: Subscription) => subscription.unsubscribe());
  }
}
  • Використання оператора takeUntil з бібліотеки rxjs у поєднанні з Subject. За допомогою цієї техніки ми все ще прописуємо хук життєвого циклу ngOnDestroy, але цього разу нема потреби в ngOnDestroy відписуватися від кожного потоку окремо.
export class DemoComponent implements OnInit, OnDestroy {

  private readonly destroy: Subject = new Subject();

  ngOnInit(): void {
    of([])
      .pipe(takeUntil(this.destroy.asObservable()))
      .subscribe();
  }

  ngOnDestroy(): void {
    this.destroy.next();
  }
}

Звісно, в такому форматі нам треба буде дублювати код в кожному компоненті, де використовуються підписки, але тут вже є декілька варіантів, як можна тримати таку логіку в одному місці, наприклад використання базового компонента, який буде містити логіку для завершення підписок і наслідувати від нього кожен свій компонент, чи використання @Decorator і каcтомних rxjs операторів, чи за допомогою бібліотеки @ngneat/until-destroy.

Нарешті вийшов Angular 16 із чудовим DestroyRef provider, який можна легко використовувати без залучення хука ngOnDestroy. Вам потрібно токен ін’єкції з DestroyRef і оператор takeUntilDestroyed з пакета @angular/core/rxjs-interop:

import { Component, DestroyRef, inject, OnInit } from '@angular/core';
import { of } from 'rxjs';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

@Component({
  selector: 'app-demo',
  templateUrl: './demo.component.html',
  styleUrls: ['./demo.component.scss'],
})
export class DemoComponent implements OnInit {

  private readonly destroy: DestroyRef = inject(DestroyRef);

  ngOnInit(): void {
    of([])
      .pipe(takeUntilDestroyed(this.destroy))
      .subscribe();
  }
}

Джерелаangular.io, blog.bitsrc.io

Поширити
guest
0 коментарів
Міжтекстові Відгуки
Переглянути всі коментарі