AngularAtlaséd. 22.2

Chap. 04Composants : communication24 / 75

Lifecycle et DestroyRef

Quels hooks comptent encore à l’ère des Signals, afterNextRender, DestroyRef et ngOnChanges typé.

v21 ~0 min de lecture Documentation officielle

Les Lifecycle hooks (ngOnInit, ngOnChanges, ngOnDestroy...) existent toujours et fonctionnent. Mais avec les Signals, la plupart deviennent inutiles : dériver depuis les inputs se fait avec computed(), réagir avec effect(), travailler sur le DOM avec afterNextRender(), et nettoyer avec DestroyRef.

Le tableau d’équivalence

Ancien hook             → Équivalent moderne
───────────────────────────────────────────────────────────────────
constructor            → constructor (DI, Signals, effect, afterNextRender)
ngOnChanges            → computed() / effect() / linkedSignal() sur les inputs
ngOnInit               → computed() / resource() (ou ngOnInit, toujours valide)
ngDoCheck              → vous n’en avez presque jamais besoin
ngAfterContentInit     → contentChild() / contentChildren() (Signals)
ngAfterViewInit        → afterNextRender() + viewChild()
ngAfterViewChecked     → afterEveryRender() (rarement)
ngOnDestroy            → inject(DestroyRef).onDestroy() / takeUntilDestroyed()

À quoi ressemble un composant moderne

import { Component, DestroyRef, afterNextRender, computed, effect, inject, input } from '@angular/core';

@Component({ selector: 'app-user-panel', /* ... */ })
export class UserPanel {
  readonly userId = input.required<number>();

  private readonly api = inject(UserApi);          // DI : dans les champs / le constructeur

  // « ngOnChanges » → computed / effect / resource sur les inputs
  readonly user = httpResource<User>(() => `/api/users/${this.userId()}`);
  readonly title = computed(() => this.user.value()?.name ?? 'Chargement…');

  constructor() {
    // « ngAfterViewInit » → afterNextRender (une fois, après le premier rendu)
    afterNextRender(() => this.chart.init(this.canvas().nativeElement));

    // « ngOnDestroy » → DestroyRef.onDestroy (fonctionne aussi dans les services, fonctions, directives)
    inject(DestroyRef).onDestroy(() => this.chart.dispose());

    // réaction au changement d’un input
    effect(() => this.analytics.track('user-panel-open', { id: this.userId() }));
  }
}
LiveL’ordre réel des hooks
(le Child n’existe pas)
  • Cliquez sur « Créer le Child ».
Créez le Child, changez les inputs, détruisez-le. Remarquez que dans le constructeur les inputs ne sont pas encore définis.

ngOnChanges avec SimpleChanges typé v21

// Besoin de ngOnChanges malgré tout ? Depuis la v21, SimpleChanges est générique :
export class Legacy implements OnChanges {
  readonly name = input('');
  readonly age = input(0);

  ngOnChanges(changes: SimpleChanges<Legacy>) {
    if (changes.name) {                       // typé, sans changes['name']
      console.log(changes.name.previousValue, '→', changes.name.currentValue);
    }
  }
}

DestroyRef : un nettoyage réutilisable

Contrairement à ngOnDestroy (qui n’existe que sur les classes), DestroyRef peut être injecté n’importe où, y compris dans des fonctions. Cela permet des « hooks » réutilisables qui se nettoient tout seuls.

// DestroyRef fonctionne partout où il y a un contexte d’injection — idéal pour des fonctions réutilisables
export function useInterval(ms: number, fn: () => void): void {
  const id = setInterval(fn, ms);
  inject(DestroyRef).onDestroy(() => clearInterval(id));
}

export class Clock {
  readonly now = signal(new Date());
  constructor() {
    useInterval(1000, () => this.now.set(new Date())); // se nettoie tout seul
  }
}

afterNextRender / afterEveryRender

// afterNextRender — une fois ; afterEveryRender — après chaque rendu de l’application (rarement nécessaire)
afterNextRender({
  read: () => this.el.nativeElement.offsetHeight,    // lit la mise en page
  // write: (height) => ...                           // puis écrit (phases séparées = pas de thrashing)
});

// S’exécute uniquement dans le navigateur (pas pendant le SSR) : le bon endroit pour window, document, localStorage
LiveDéfiler jusqu’au dernier message : dans le gestionnaire de clic ou après le rendu ?

#1 Le build est passé ?

#2 Oui, et tous les tests sont verts.

#3 Alors j’ouvre la PR.

#4 Préviens-moi quand elle est mergée.

send() {
  this.messages.update((list) => [...list, next]);
  const el = this.chat().nativeElement;
  el.scrollTop = el.scrollHeight; // le DOM a encore l’ancienne liste
}
Dans le gestionnaire de clic, le DOM affiche encore l’ancienne liste (il est mis à jour au prochain rendu) : scrollHeight est donc l’ancienne hauteur. afterRenderEffect s’exécute une fois le DOM mis à jour.

Le nettoyage des abonnements, timers et listeners est détaillé dans Fuites mémoire : les trouver et les corriger ; le code qui touche window ou document doit aussi tourner sur le serveur : Code compatible serveur.

Quand OUI, quand NON

Vous utilisez encore les hooks classiques
  • Du code existant qui fonctionne : inutile de forcer une réécriture.
  • ngOnInit pour une initialisation qui lit les inputs une seule fois (il reste valide et lisible).
  • Interfaces exigées par des bibliothèques (p. ex. le ControlValueAccessor classique).
Utilisez l’équivalent moderne
  • Recalculer une valeur quand un input change → computed().
  • Réinitialiser un état local quand un input change → linkedSignal().
  • Charger des données quand un input change → httpResource().
  • Se désabonner dans ngOnDestroy → takeUntilDestroyed() / toSignal.

Pièges fréquents

  • Les inputs dans le constructeur : ils ne sont pas définis. Lire un input.required à cet endroit lève une erreur.
  • window/document dans le constructeur avec SSR → une erreur côté serveur. Déplacez le code dans afterNextRender.
  • ngOnChanges ne se déclenche pas pour les mutations internes des objets reçus, seulement pour les nouvelles références.

Chap. 04 · 0 sur 6 terminées

Leçon terminée ?

Marquez-la : elle apparaîtra sur votre carte, dans le sommaire et sur la page d’accueil.

Se marque toute seule une fois la leçon lue en entier.

  1. input() et output()
  2. model() — binding bidirectionnel
  3. viewChild et contentChild
  4. Lifecycle et DestroyRef
  5. Projection de contenu
  6. ng-template et ngTemplateOutlet
Voir toute votre carte

Les 75 pages · tapez pour filtrer

  • 01Nouveautés d’Angular 21 & 22Tous les changements importants de la v21 et de la v22, en bref, avec un lien vers la page qui explique chacun.Départ
  • 01Votre première application, pas à pasUne liste de lecture construite d’un composant vide jusqu’à une application terminée — signals, @for, inputs et outputs, un service et un formulaire, pas à pas.Départ
  • 01Décisions rapides« Où mettre ça ? », « Signal ou Observable ? », « Shared ou feature ? » — des réponses courtes aux questions de tous les jours.Départ
  • 01Questions d’entretien Angular60 vraies questions d’entretien pour profils junior, confirmé et senior, avec la réponse à donner, la relance et les signaux d’alerte. Plus un entretien blanc.Départ
  • 02Standalone et bootstrapComment une application démarre sans NgModule : bootstrapApplication, app.config.ts, imports dans le composant.Fondamentaux modernes
  • 02Data binding et événementsInterpolation, bindings de propriétés et d’attributs, événements avec $event et filtres de touches, et comment [( )] est construit — ce qui entre dans le DOM et ce qui en revient.Fondamentaux modernes
  • 02Control Flow : @if, @for, @switchLa syntaxe de blocs qui remplace *ngIf/*ngFor/ngSwitch, avec track, @empty et vérifications d’exhaustivité.Fondamentaux modernes
  • 02@let et les nouvelles expressions de templateVariables locales avec @let, fonctions fléchées, spread, regex, instanceof, commentaires dans les balises.Fondamentaux modernes
  • 02@defer — Lazy Loading dans les templatesChargez les composants lourds uniquement quand c’est nécessaire : triggers, prefetch, placeholder, loading, error.Fondamentaux modernes
  • 02Bindings de classe et de stylePourquoi [class.x] et [style.x] ont remplacé ngClass et ngStyle (avec migration automatique depuis la v21).Fondamentaux modernes
  • 02Styles des composants et encapsulation:host, les trois modes d’encapsulation, les thèmes avec des variables CSS, et pourquoi ::ng-deep est un dernier recours.Fondamentaux modernes
  • 02Pipes : quand et commentPipes pures vs impures, pipes personnalisées, et comment choisir entre une pipe, computed() et une méthode.Fondamentaux modernes
  • 03signal() et computed()Les primitives réactives : état modifiable, état dérivé, égalité, untracked et règles d’immutabilité.Signals et réactivité
  • 03effect() — quand OUI, quand NONEffets de bord synchronisés avec les Signals : localStorage, logs, API impératives. Et leurs pièges.Signals et réactivité
  • 03linkedSignal() — état dérivé modifiableUn signal qui se réinitialise quand sa source change, mais que vous pouvez aussi modifier à la main.Signals et réactivité
  • 03resource, rxResource, httpResourceDes données asynchrones sous forme de Signals : status, value, error, reload, annulation automatique. Stable depuis la v22.Signals et réactivité
  • 03debounced() — signals différésLa version « debounce » d’un signal, sans RxJS. Parfait pour la recherche.Signals et réactivité
  • 03Listes : rechercher, filtrer, trier, paginerUne chaîne de signals computed qui ne recalcule que ce qui a changé, avec les filtres dans l’URL pour qu’un lien rouvre la même vue.Signals et réactivité
  • 03Les Observables depuis zéroCe qu’est un Observable, subscribe et unsubscribe, les opérateurs que vous utilisez chaque semaine, froid ou chaud — et quand un signal suffit.Signals et réactivité
  • 03Signals ↔ RxJStoSignal, toObservable, takeUntilDestroyed, outputFromObservable — et quand RxJS reste le bon choix.Signals et réactivité
  • 04input() et output()Les inputs comme Signals (required, transform, alias) et les outputs typés. Les données descendent, les événements remontent.Composants : communication
  • 04model() — binding bidirectionnelLe « banana-in-a-box » [( )] avec une seule API. Quand l’utiliser, et quand input + output est préférable.Composants : communication
  • 04viewChild et contentChildLes queries comme Signals : viewChild, viewChildren, contentChild, contentChildren, l’option read.Composants : communication
  • 04Lifecycle et DestroyRefQuels hooks comptent encore à l’ère des Signals, afterNextRender, DestroyRef et ngOnChanges typé.Composants : communication
  • 04Projection de contenung-content avec select, plusieurs slots, contenu par défaut et le piège de la projection conditionnelle.Composants : communication
  • 04ng-template et ngTemplateOutletLes templates comme valeurs : les render props en Angular, contexte typé et personnalisation des composants.Composants : communication
  • 05Smart vs DumbContainer vs présentation : qui détient l’état, qui se contente d’afficher, et comment bien les séparer.Conception des composants
  • 05Composants génériques <T>Un DataTable<T> ou un Select<T> correctement typé, avec des templates pour les cellules.Conception des composants
  • 05Composants dynamiquesNgComponentOutlet, createComponent avec inputBinding/outputBinding, et un tableau de bord construit à partir d’une configuration.Conception des composants
  • 05Directives et composition d’hôteLes directives d’attribut, les métadonnées host: {} et la Directive Composition API (hostDirectives).Conception des composants
  • 05Contrôles de formulaire personnalisésFormValueControl (Signal Forms) vs ControlValueAccessor : une notation par étoiles, dans les deux variantes.Conception des composants
  • 05Change DetectionOnPush est la valeur par défaut depuis la v22, Zone.js a disparu depuis la v21. Ce qui déclenche le rendu et comment éviter les mauvaises surprises.Conception des composants
  • 06inject() et @Service()Le nouveau décorateur @Service() de la v22, inject() vs le constructeur, et le contexte d’injection.Dependency Injection
  • 06Providers et hiérarchie des injecteursRoot vs route vs composant, useClass/useValue/useFactory/useExisting, et les modificateurs optional/self/skipSelf.Dependency Injection
  • 06InjectionToken et provideX()Configuration typée, fonctions provideFeature(), makeEnvironmentProviders et initializers.Dependency Injection
  • 06injectAsync() — services en Lazy LoadingChargez un service lourd uniquement quand vous en avez besoin, avec prefetch à l’idle.Dependency Injection
  • 07Structure des dossierscore / shared / features, ce que contient chacun, et à quoi ressemble l’intérieur d’une feature.Architecture d’application
  • 07Shared vs featureQuand déplacer un composant dans shared et (surtout) quand NE PAS le faire. Une checklist concrète.Architecture d’application
  • 07Interfaces et modèlesInterface en ligne ou fichier séparé ? DTO vs modèle de domaine, type vs interface, où les ranger.Architecture d’application
  • 07State Management avec les SignalsStores simples à base de Signals, facades, état local vs global, et quand NgRx devient nécessaire.Architecture d’application
  • 07Guide de style et nommageLes conventions officielles actuelles : noms de fichiers sans suffixes, protected, readonly, ordre des membres.Architecture d’application
  • 07Barrels, alias et frontièresindex.ts, alias de chemins, API publique d’une feature et règles de dépendances vérifiables automatiquement.Architecture d’application
  • 07Erreurs : @boundary et ErrorHandlerLe nouveau bloc @boundary de la v22.2, l’ErrorHandler global, les erreurs HTTP et les erreurs de resource.Architecture d’application
  • 08Routing moderne et Lazy LoadingloadComponent, routes enfants, paramètres comme inputs et héritage des paramètres (le nouveau comportement par défaut de la v22).Routing
  • 08Guards et resolverscanActivate, canMatch, canDeactivate et resolve sous forme de fonctions, avec redirections via UrlTree / RedirectCommand.Routing
  • 09Signal Forms — les basesDes formulaires bâtis sur les Signals : form(), [formField], validation par schéma. Stable depuis la v22.Formulaires
  • 09Signal Forms — avancéValidation personnalisée et inter-champs, async/HTTP avec debounce, listes dynamiques, désactivé/masqué, schémas réutilisables.Formulaires
  • 09Reactive Forms typésFormGroup typé, nonNullable, FormArray — et leur cohabitation avec les Signal Forms.Formulaires
  • 10HttpClient, interceptors et couche d’APIHttpClient sans configuration (v21), Fetch par défaut (v22), interceptors fonctionnels et une couche d’API avec mapping des DTO.HTTP et données
  • 11Performance — une checklistCe qui compte vraiment : OnPush + Signals, track, @defer, routes en Lazy Loading, images, bundles et Hydration.Qualité et performance
  • 11Tests avec VitestVitest est le runner par défaut depuis la v21. TestBed, composants avec Signals, services, HTTP et harnesses.Qualité et performance
  • 11DevTools : regarder dans votre applicationChrome DevTools et Angular DevTools pas à pas : ce que montre chaque panneau, avec des exercices qui fonctionnent sur ce site.Qualité et performance
  • 11Angular AriaDes composants headless et accessibles que vous stylez comme vous voulez : tabs, accordion, menu, listbox...Qualité et performance
  • 12SSR, Prerendering et modes de renduQuand rendre sur le serveur, quand au build et quand uniquement dans le navigateur : RenderMode par route, app.routes.server.ts et les coûts réels.SSR et Hydration
  • 12Hydration : event replay et incrémentaleComment le navigateur reprend le HTML du serveur sans le re-rendre : Hydration complète, event replay, @defer (hydrate on …) et erreurs de mismatch.SSR et Hydration
  • 12Code compatible serveurwindow n’existe pas sur le serveur : PLATFORM_ID, afterNextRender, DOCUMENT, TransferState, le cache HTTP et PendingTasks.SSR et Hydration
  • 13Micro frontendsQuand découper une application en plusieurs déploiements vaut le coup, et quand c’est juste de la complexité : Native Federation, Module Federation, iframes, Web Components.Architecture à grande échelle
  • 13Web Components avec Angular ElementscreateCustomElement : un composant Angular utilisé comme balise HTML n’importe où, plus la communication entre applications via des événements et BroadcastChannel.Architecture à grande échelle
  • 13Monorepo, bibliothèques et frontièresUn workspace avec plusieurs applications et bibliothèques : ng generate library, Nx, points d’entrée secondaires, publication et règles de dépendances.Architecture à grande échelle
  • 13Architecture hexagonale (ports et adapters)Un domaine sans Angular, des ports sous forme de classes abstraites et des adapters interchangeables : HTTP, localStorage ou en mémoire, sans toucher à l’UI.Architecture à grande échelle
  • 14Les Signals sous le capotLe graphe réactif : producteurs et consommateurs, push-pull, pourquoi computed est lazy et sans glitch, le problème du diamant et quand les effects s’exécutent.Réactivité avancée
  • 14RxJS avancé : opérateurs d’ordre supérieurswitchMap, mergeMap, concatMap et exhaustMap sur un diagramme interactif, plus retry avec backoff, shareReplay et comment éviter les fuites.Réactivité avancée
  • 14NgRx SignalStoreState Management à grande échelle sur les Signals : withState, withComputed, withMethods, rxMethod, entités et hooks — et quand un store simple suffit.Réactivité avancée
  • 14Machines à états avec les signalsFini les états impossibles : une machine typée sur des signals, avec transitions, gardes et un diagramme d’états en direct.Réactivité avancée
  • 15WebSockets : un temps réel qui résiste au réseauUn socket typé sous forme de signals : reconnexion avec backoff et jitter, heartbeat, file d’attente hors ligne et sécurité SSR.Temps réel et hors ligne
  • 15Mises à jour optimistes et rollbackUne UI instantanée qui reste honnête : snapshot et rollback, réponses dans le désordre, clés d’idempotence.Temps réel et hors ligne
  • 15Offline-first : Service Worker et cacheLe Service Worker d’Angular : stratégies de cache, annonce des nouvelles versions et file d’attente pour les modifications faites hors ligne.Temps réel et hors ligne
  • 16Web WorkersDes calculs lourds sans bloquer l’UI : un vrai worker dans la page, l’échange de messages et quand ça n’en vaut pas la peine.UI avancée et performance
  • 16Listes géantes : virtual scroll100 000 lignes sans latence : le virtual scroll du CDK, itemSize, trackBy et les alternatives (pagination, scroll infini).UI avancée et performance
  • 16Animations modernes et View Transitionsanimate.enter et animate.leave à la place de @angular/animations (déprécié), transitions CSS et View Transitions à la navigation.UI avancée et performance
  • 16Fuites mémoire : les trouver et les corrigerAbonnements, timers et listeners qui survivent à leur composant — comment les repérer dans les DevTools et les fermer.UI avancée et performance
  • 17Sécurité : XSS, sanitisation et CSPCe qu’Angular fait automatiquement contre le XSS, quand bypassSecurityTrust devient dangereux, plus la CSP avec nonce, Trusted Types et XSRF.Sécurité et internationalisation
  • 17Authentification : tokens et refreshUn interceptor qui ajoute le token, le renouvelle une seule fois sur une 401 et rejoue les requêtes en attente — plus où conserver le token.Sécurité et internationalisation
  • 17OAuth 2.1 et OpenID Connect avec PKCELe flux authorization code avec PKCE, pas à pas : verifier et challenge, state et nonce, l’ID token, et pourquoi un BFF est plus sûr.Sécurité et internationalisation
  • 17Internationalisation (i18n)$localize, l’attribut i18n, ICU plural/select, un build par langue vs des traductions à l’exécution, et le formatage selon la locale.Sécurité et internationalisation