Les nouveautés d'Angular 19 en 4 minutes

Angular 19 vient de sortir, et il y a beaucoup de nouveautés intéressantes : hydratation incrémentale, linkedSignal, l'API des ressources, et plein d'autres choses. Venez découvrir tout ça en moins de 4 minutes !

Skip to content

Vous souhaitez recevoir de l'aide sur ce sujet ? rejoignez la communauté Angular.fr sur Discord.

DestroyRef et takeUntilDestroyed : Gérer la destruction des composants dans Angular

Angular 16+

DestroyRef est une nouvelle fonctionnalité introduite dans Angular 16+.

Comprendre DestroyRef par un exemple concret

Imaginez que vous ayez une application de messagerie instantanée. Quand un utilisateur quitte une conversation, vous devez vous assurer que toutes les souscriptions aux messages sont correctement arrêtées pour éviter les fuites mémoire. C'est exactement ce que DestroyRef nous aide à faire !

Implémentation Technique

Commençons par voir comment utiliser DestroyRef dans notre application de gestion d'utilisateurs.

ts
import { Component, DestroyRef, inject } from '@angular/core';
import { UserService } from '../../core/services/user.service';
import { User } from './user.interface';

@Component({
  selector: 'app-user',
  standalone: true,
  template: `
    @if (user) {
      <div>{{ user.name }}</div>
    }
  `
})
export class UserComponent {
  private userService = inject(UserService);
  private destroyRef = inject(DestroyRef);
  user: User | null = null;

  constructor() {
    this.userService.getUser(1).subscribe(user => {
      this.user = user;
    });

    this.destroyRef.onDestroy(() => {
      // Logique de nettoyage
      console.log('Composant détruit, nettoyage effectué');
    });
  }
}

ASTUCE

DestroyRef est particulièrement utile pour créer des fonctions réutilisables de nettoyage que vous pouvez utiliser dans plusieurs composants.

Création d'une Fonction Réutilisable

Voici comment créer une fonction utilitaire pour gérer les souscriptions :

ts
export function destroyScope() {
  const subscriptions = new Subscription();
  inject(DestroyRef).onDestroy(() => {
    subscriptions.unsubscribe();
  });
  return subscriptions;
}

Utilisation dans un composant :

ts
import { Component } from '@angular/core';
import { destroyScope } from './utils';

@Component({
  selector: 'app-user-list',
  standalone: true,
  template: `
    @for (user of users; track user.id;) {
      <div>{{ user.name }}</div>
    }
  `
})
export class UserListComponent {
  private subscriptions = destroyScope();
  users: User[] = [];

  constructor(private userService: UserService) {
    this.subscriptions.add(
      this.userService.getUsers().subscribe(users => {
        this.users = users;
      })
    );
  }
}

ATTENTION

La fonction destroyScope() ne peut être utilisée que dans un contexte d'injection (constructor ou initialisation de propriété). Elle ne fonctionnera pas dans ngOnInit() ou d'autres méthodes du cycle de vie.

Différence avec ngOnDestroy

DestroyRef offre plusieurs avantages par rapport à ngOnDestroy :

  1. Injection de dépendances plutôt qu'implémentation d'interface
  2. Possibilité de créer des fonctions utilitaires réutilisables
  3. Plus flexible dans son utilisation
ts
// Approche traditionnelle avec ngOnDestroy
export class TraditionalComponent implements OnDestroy {
  ngOnDestroy() {
    // Logique de nettoyage
  }
}

// Approche moderne avec DestroyRef
export class ModernComponent {
  constructor(destroyRef: DestroyRef) {
    destroyRef.onDestroy(() => {
      // Logique de nettoyage
    });
  }
}

Utilisation de takeUntilDestroyed

takeUntilDestroyed est un opérateur RxJS spécialement conçu par Angular qui permet de gérer automatiquement la destruction des observables. C'est une alternative plus élégante à notre fonction destroyScope.

ASTUCE

takeUntilDestroyed est disponible depuis Angular 16 dans @angular/core/rxjs-interop.

Voici comment l'utiliser :

ts
import { Component, inject } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { UserService } from '../../core/services/user.service';
import { User } from './user.interface';

@Component({
  selector: 'app-user',
  standalone: true,
  template: `
    @if (user) {
      <div>{{ user.name }}</div>
    }
  `
})
export class UserComponent {
  private userService = inject(UserService);
  user: User | null = null;

  constructor() {
    // L'observable sera automatiquement détruit quand le composant sera détruit
    this.userService.getUser(1).pipe(
      takeUntilDestroyed()
    ).subscribe(user => {
      this.user = user;
    });
  }
}

Utilisation hors du constructeur

Si vous devez utiliser takeUntilDestroyed en dehors du constructeur, vous devez injecter explicitement DestroyRef :

ts
import { Component, DestroyRef, inject } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { UserService } from '../../core/services/user.service';
import { User } from './user.interface';

@Component({
  selector: 'app-user-list',
  standalone: true,
  template: `
    @for (user of users; track user.id;) {
      <div>{{ user.name }}</div>
    }
  `
})
export class UserListComponent {
  private destroyRef = inject(DestroyRef);
  users: User[] = [];

  ngOnInit() {
    this.userService.getUsers().pipe(
      takeUntilDestroyed(this.destroyRef)
    ).subscribe(users => {
      this.users = users;
    });
  }
}

ATTENTION

takeUntilDestroyed() sans paramètre ne peut être utilisé que dans un contexte d'injection (comme le constructeur). Pour l'utiliser ailleurs, vous devez passer explicitement DestroyRef.

BONNE PRATIQUE

  1. Syntaxe plus concise que DestroyRef.onDestroy()
  2. Intégration native avec RxJS
  3. Pas besoin de gérer manuellement les souscriptions
  4. Meilleure lisibilité du code

Préférez takeUntilDestroyed à DestroyRef.onDestroy() quand vous travaillez avec des observables, car c'est plus idiomatique et plus facile à maintenir.

Chaque mois, recevez en avant-première notre newsletter avec les dernières actualités, tutoriels, astuces et ressources Angular directement par email !