Introduction
Avec Angular 18, le modèle réactif s'enrichit grâce aux Signals, une API légère pour représenter l'état réactif local. Les Signals permettent de gérer l'état, de dériver des valeurs et de réagir aux changements de manière plus prévisible et performante qu'avec certaines approches classiques (services RxJS pour tout). Cet article présente les concepts essentiels, des patterns pratiques et des conseils de performance.
Concepts clés
Qu'est-ce qu'un Signal ?
Un Signal est une valeur réactive mutée explicitement. Contrairement aux Observables, un signal contient l'état courant et notifie automatiquement ses consommateurs lorsqu'il change. Les trois primitives principales :
- signal : valeur mutable et observable
- computed : valeur dérivée et mémoïsée
- effect : exécute du code de bord en réponse aux changements
Pourquoi les Signals ?
Les Signals réduisent la complexité liée aux subscriptions et à la gestion manuelle du cycle de vie. Ils s'intègrent naturellement au moteur de détection de changements d'Angular et permettent d'éviter les re-renders inutiles grâce à la mémoïsation et aux dépendances explicites.
API de base et exemples
Créer et utiliser un Signal
Exemple minimal dans un composant :
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-counter',
template: `
Compteur : {{ counter() }}
`
})
export class CounterComponent {
counter = signal(0);
increment() {
this.counter.update(c => c + 1);
}
}
Valeurs dérivées avec computed
Utilisez computed pour créer des valeurs dérivées qui se recalculent uniquement quand leurs dépendances changent.
import { computed, signal } from '@angular/core';
const count = signal(5);
const isEven = computed(() => count() % 2 === 0);
// isEven() renverra true ou false, recalculé seulement si count change
Effets avec effect
Les effects sont utiles pour synchroniser l'état avec l'extérieur (API, localStorage) ou déclencher des opérations secondaires.
import { effect } from '@angular/core';
effect(() => {
console.log('Le compteur a changé :', count());
});
Intégration avancée et patterns
Interopérabilité avec RxJS
Vous pouvez convertir un Observable en Signal via toSignal() (API d'exemple selon version). Cela facilite la transition progressive depuis RxJS :
import { toSignal } from '@angular/core/rxjs-interop';
const dataSignal = toSignal(apiObservable, { initialValue: null });
Stockage d'état local vs. global
- Pour un état local (composant), privilégiez un signal dans le composant.
- Pour un état global, créez un service encapsulant des signals : exposez des getters et des méthodes de mutation pour conserver l'encapsulation.
Performance et bonnes pratiques
Éviter les re-calculs inutiles
- Préférez computed aux calculs dans le template si la logique est coûteuse.
- Regroupez les mutations pour diminuer le nombre de notifications : utilisez plusieurs update() ponctuels plutôt qu'une cascade d'opérations atomiques.
Utiliser des effects avec précaution
Les effets déclenchent du code secondaire : ne surchargez pas un effect avec des opérations lourdes non asynchrones. Si vous devez exécuter quelque chose d'asynchrone, organisez le flux et nettoyez correctement (retours d'abonnement, abort controllers).
Debugging
- Loggez les valeurs clés dans des effects contrôlés.
- Surveillez les dépendances de vos computed pour éviter les références implicites à des variables non-réactives.
- Profitez des outils Angular et des extensions pour inspecter la hiérarchie des composants et l'état des signals.
Migrations et pièges courants
Lors de la migration depuis RxJS intensif :
- Ne remplacez pas mécaniquement tous les Observables par des Signals — chaque abstraction a sa valeur.
- Conservez RxJS pour les flux complexes, combinaisons temporelles ou multicasting avancé.
- Rechiffrez le design : Signals conviennent mieux à l'état synchrone local et aux dérivations purement calculables.
Exemple complet : gestion d'un formulaire filtré
Architecture recommandée : un service contenant les signals pour les filtres, un computed pour la requête générée et un effect pour charger les résultats.
Conclusion
Les Signals d'Angular 18 offrent un modèle clair pour la gestion d'état réactive et performante. En combinant signal, computed et effect, on obtient des applications plus prévisibles, plus faciles à optimiser et à maintenir. Adoptez-les progressivement, testez les patterns, et mesurez l'impact sur la performance avant une refonte complète.
Ressources : documentation officielle Angular, guides de migration, et exemples officiels de patterns avec Signals.
À propos de l'expert
Laty Gueye Samba est un développeur full stack basé à Dakar, passionné par l'architecture logicielle. Spécialiste des écosystèmes Java (Spring Boot) et Angular.