Cours Angular · Module 6: Signals
Les effects - quand la fumée doit faire réagir quelqu'un hors des murs
Dans cette leçon9
Les deux relais précédents ont enfermé toute la circulation des nouvelles à l'intérieur des murs de l'Académie. Un signal garde une valeur, le scribe de computed() la recalcule et l'inscrit sur son ardoise, le template affiche l'un et l'autre., tout cela se déroule dans un circuit parfaitement étanche : une valeur entre, une valeur sort, et au bout du compte quelqu'un regarde la muraille.
Tôt ou tard, tu tomberas pourtant sur une tâche qui ne tient pas dans ce circuit. Le chroniqueur de l'Académie doit consigner dans son registre chaque changement du nombre de patrouilles envoyées sur la route, pour qu'on puisse des années plus tard reconstituer ce qui s'est passé. Le thème d'interface choisi par l'élève doit survivre à la fermeture du navigateur, il faut donc le déposer quelque part. La garde de la porte doit envoyer un messager au château voisin dès que l'alerte dépasse un seuil. Une carte dessinée par une bibliothèque étrangère, qui n'a jamais entendu parler d'Angular, doit être redessinée dès que la route sélectionnée change.
Aucune de ces tâches n'est une valeur. On ne peut ni les calculer ni les renvoyer, car elles n'ont pas de résultat : elles font simplement quelque chose en dehors de l'application. Elles ajoutent une ligne à un journal, écrivent dans la mémoire du navigateur, envoient une requête, réveillent du code étranger. Les développeurs appellent ces actions des effets de bord, en anglais side effects : tout ce qu'une fonction accomplit au-delà de renvoyer un résultat.
Le scribe de la leçon précédente se prête très mal à ce travail, et il vaut la peine de savoir pourquoi, car la tentation est grande. D'abord, computed() doit renvoyer quelque chose : c'est sa seule mission. Ensuite, et c'est la raison décisive, le scribe travaille paresseusement. Au relais précédent, nous avons constaté que la fonction confiée à computed() ne s'exécute pas une seule fois tant que personne ne lit son résultat. Un registre tenu par le scribe ne contiendrait donc des entrées que les jours où quelqu'un a jeté un oeil sur l'ardoise, et le jour où personne ne monte sur la muraille, la page resterait blanche. Il te faut quelqu'un qui parte de lui-même, sans qu'on le lui demande, et qui ait le droit de franchir la porte.
L'ordre donné au chroniqueur
Ce quelqu'un s'appelle un effect, et on le met en place avec la fonction effect() du paquet @angular/core - celui-là même d'où viennent signal(), computed() et le décorateur @Component. Tu lui passes un seul argument : la fonction qui contient ce qui doit se produire. Dans sa forme la plus simple, cette fonction ne prend aucun paramètre, et tu découvriras vers la fin de la leçon le seul paramètre utile qu'elle puisse recevoir. Angular l'exécutera de lui-même, dans deux situations différentes. Une première fois au démarrage, juste après la création de l'effect, pour que le registre soit dès la première seconde en accord avec l'état des tours. Puis à nouveau après chaque changement de n'importe lequel des signals lus à l'intérieur. Tu ne déclares rien, tu ne t'abonnes à rien, il n'existe aucune liste de dépendances à recopier à la main : il suffit que tu appelles le signal avec ses parenthèses.
Commençons par le plus petit effect possible, histoire de voir la forme de l'appel toute nue. Admettons que tu disposes quelque part d'un signal nommé count, et que la seule chose que tu veuilles soit d'afficher sa valeur dans la console après chaque changement.
1effect(() => console.log(count()));Cette seule ligne constitue un effect entier, et il n'y manque rien. Retiens-la comme quatre morceaux toujours rangés dans le même ordre : le nom effect, puis l'ouverture de l'appel accompagnée de la flèche sans argument, c'est-à-dire (() =>, puis l'expression console.log(count()) elle-même, et enfin la parenthèse fermante ). Le corps de la fonction se réduit ici à une seule expression, les accolades sont donc inutiles : c'est la même forme abrégée de fonction fléchée que celle rencontrée avec computed(). Remarque surtout ce que cette ligne ne contient pas. Aucun nom de signal posé à côté en guise de dépendance, aucun mot subscribe, aucun this.detectChanges(). Angular apprendra que l'effect regarde count pour une seule et unique raison : lors du premier passage, quelqu'un a lu ce signal.
Une chose, en revanche, ne pardonne pas : tu ne peux pas poser cette ligne n'importe où. Un effect doit naître dans un contexte d'injection, autrement dit là où Angular sait à quelle vie le rattacher. En pratique, cela veut dire le constructeur d'une classe ou l'initialiseur d'un champ, exactement les deux endroits où tu appelais inject() dans le module consacré aux guildes. J'ai vérifié sur du code en fonctionnement ce qui arrive ailleurs : l'appel se solde par une erreur NG0203 dont le message annonce que effect() ne peut être utilisé que dans un contexte d'injection, tel qu'un constructeur, une fonction fabrique ou un initialiseur de champ.
Le chroniqueur dans un composant
Bâtissons donc un véritable chroniqueur. Le composant surveille un seul nombre : combien de patrouilles ont été envoyées sur la route. Nous appellerons ce signal patrols et il part de zéro. La méthode sendPatrol() l'augmente de un en se servant de update(), l'ordre de la leçon précédente, puisque la nouvelle valeur découle de l'ancienne. Le seul élément neuf est le constructeur, et à l'intérieur un unique appel à effect() qui inscrit chaque nouvel état dans le registre. Le reste de l'écriture t'est familier depuis le premier module : le décorateur @Component avec son sélecteur, la marque du composant autonome et son template, ainsi que la liaison d'événement (click).
1import { Component, signal, effect } from '@angular/core';
2
3@Component({
4 selector: 'app-patrol-log',
5 standalone: true,
6 template: '<button (click)="sendPatrol()">Envoyer une patrouille</button>'
7})
8export class PatrolLogComponent {
9 patrols = signal(0);
10
11 constructor() {
12 effect(() => console.log('Patrouilles sur la route :', this.patrols()));
13 }
14
15 sendPatrol(): void {
16 this.patrols.update(v => v + 1);
17 }
18}J'ai exécuté ce composant et le déroulement est exactement celui que j'ai annoncé. Juste après le premier affichage, avant même que quiconque ait touché le bouton, une entrée avec un zéro apparaît dans le registre. C'est important et cela surprend souvent : un effect s'exécute au moins une fois de lui-même, sans quoi le registre commencerait au premier changement et tu ignorerais de quoi l'on est parti. Après un clic sur le bouton, une deuxième entrée s'ajoute, avec un un.
Le plus intéressant reste ce qui n'a pas été touché. La méthode sendPatrol() est identique à celle des composants des relais précédents : elle augmente le signal de un et s'arrête là, elle ignore jusqu'à l'existence du chroniqueur et ne contient pas une seule ligne au sujet du registre. Le signal patrols n'a pas changé non plus : c'est toujours un signal inscriptible ordinaire, tu le lis toujours avec des parenthèses, tu peux toujours l'afficher dans le template. Aucune méthode de cycle de vie du deuxième module n'est venue s'ajouter : pas de ngOnInit, rien qu'il faille déclencher à la main. L'effect s'est accroché sur le côté, et il regarde.
Cette unilatéralité est une qualité, pas un manque. Le signal ignore combien il a d'observateurs, et il n'a pas besoin de le savoir ; ajouter un deuxième, un troisième et un dixième effect qui lisent patrols ne réclame chez lui aucune modification. La tour de la première leçon fonctionnait déjà ainsi : le guetteur allume sa fumée et retourne à ses affaires, et savoir qui la regarde est une tout autre histoire.
Ce qu'un effect suit, et ce qu'il ne suit pas
Puisque Angular construit la liste des dépendances à partir de ce que l'effect a réellement lu, cette liste se refait à neuf à chaque passage. Les conséquences sont parfois déroutantes, alors regardons-les sur un exemple. Ajoutons au composant un deuxième signal, chronicleOpen, un simple marqueur qui dit si le registre est ouvert en ce moment. Quand il est fermé, le chroniqueur n'inscrit rien - et par conséquent il ne va pas non plus regarder la tour des patrouilles.
1constructor() {
2 effect(() => {
3 if (this.chronicleOpen()) {
4 console.log('Patrouilles sur la route :', this.patrols());
5 }
6 });
7}J'ai vérifié sur un effect en fonctionnement et le résultat ne laisse aucune place au doute. Tant que chronicleOpen renvoie vrai, chaque changement de patrols relance l'effect, parce que ce signal a été lu lors du dernier passage. Mais il suffit de mettre chronicleOpen à faux pour que la condition cesse de laisser entrer l'exécution - et dès cet instant, les changements de patrols ne réveillent plus l'effect une seule fois, puisque personne n'a lu cette tour au dernier passage. Une dépendance n'est pas attribuée une fois pour toutes à un signal ; elle est le compte rendu de ce que l'effect a regardé la dernière fois.
Et rien n'a changé au passage dans les signaux eux-mêmes : les deux tours sont debout, les deux portent des valeurs à jour, et la lecture this.patrols() en n'importe quel autre endroit du programme renvoie toujours le vrai nombre. Seul le chroniqueur s'est endormi.
Il vaut la peine de connaître trois autres comportements, tous vérifiés sur du code qui tourne, car ils t'épargneront des heures d'étonnement. Premièrement, écrire dans un signal la valeur qu'il portait déjà ne relance pas l'effect : Angular compare la nouvelle valeur à l'ancienne et, faute de différence, ne réveille personne. Deuxièmement, si tu modifies dans le même tour deux signaux que l'effect regarde, il ne s'exécutera qu'une seule fois, et non deux ; les changements sont ramassés et réglés ensemble. Troisièmement, et c'est le plus sournois : seules les lectures faites immédiatement dans le corps de l'effect sont suivies. Un signal lu à l'intérieur d'un setTimeout, dans la réponse d'une requête réseau ou dans une autre fonction appelée plus tard ne deviendra pas une dépendance, car au moment où Angular observait le passage, personne ne l'avait encore appelé.
Un effect n'est pas un scribe
Voici maintenant l'erreur la plus fréquente, celle que tout le monde commet au premier contact avec les effects. Le composant doit afficher le nombre de gardes en service, et ce nombre découle de deux tours : le nombre de patrouilles patrols et l'effectif d'une patrouille guardsPerPatrol. Puisqu'un effect se déclenche après chaque changement, on est tenté de s'en servir pour faire le calcul et déposer le résultat dans un troisième signal.
1// A NE PAS FAIRE - un effect dans le role d'une valeur derivee
2guardsOnDuty = signal(0);
3
4constructor() {
5 effect(() => {
6 this.guardsOnDuty.set(this.patrols() * this.guardsPerPatrol());
7 });
8}Je l'avoue honnêtement : ce code marche. Je l'ai essayé sur un effect en fonctionnement sous Angular 19 - l'écriture dans un signal depuis l'intérieur d'un effect passe sans la moindre erreur, guardsOnDuty reçoit le bon nombre et se met à jour après chaque changement de ses composantes. Et pourtant, c'est une mauvaise solution, et je veux que tu saches précisément pourquoi, car "ça marche" et "c'est bien" sont deux choses différentes.
Il y a trois raisons. La première : tu as désormais deux sources de vérité au lieu d'une. Le nombre de gardes existe dans une tour séparée que n'importe qui peut écraser à tout instant par un set() venu d'un tout autre endroit, et rien ne l'en empêchera. La deuxième : le résultat est périmé pendant un court moment. L'effect ne s'exécute pas dans la même milliseconde que l'écriture dans patrols, il existe donc un instant où les patrouilles sont déjà plus nombreuses et les gardes encore aussi peu qu'avant. Je l'ai mesuré sur du code qui tourne : entre l'écriture et le passage de l'effect, la lecture renvoie bel et bien l'ancien nombre. La troisième : pour voir la valeur correcte, il faut que quelqu'un l'inscrive dans le signal - tu as donc ajouté à l'application une étape dont il faut se souvenir. Toute la leçon sur le scribe consistait justement à ne pas avoir de telles étapes.
La bonne solution tient sur une ligne et tu la connais depuis le relais précédent.
1guardsOnDuty = computed(() => this.patrols() * this.guardsPerPatrol());Ici, il n'y a plus rien à surveiller. La valeur se calcule toute seule à partir des deux tours, personne ne la fixe jamais et personne ne peut l'écraser, car la méthode set() n'existe tout simplement pas sur une valeur dérivée - je l'ai vérifié, la propriété vaut undefined. Il n'y a pas non plus d'instant de décalage : la lecture guardsOnDuty() renvoie toujours un nombre en accord avec l'état actuel de ses composantes. Mon conseil est ici sans condition : si ce que tu veux faire peut se formuler comme "un résultat calculé à partir de signaux", ce n'est pas un travail pour un effect mais pour computed(). Tu ne prends un effect que lorsqu'il ne s'agit pas d'un résultat, mais d'une action en dehors de l'application.
C'est aussi ici que se trouve la réponse à une question qui revient souvent : non, un effect ne sert pas à combiner plusieurs signals. Combiner, c'est justement le métier de computed(), parce que lui renvoie une valeur. La fonction confiée à effect() n'a aucun moyen de renvoyer quoi que ce soit - son résultat ne va nulle part et personne ne le lit, tandis que l'appel effect() lui-même rend une poignée vers l'effect, et surtout pas un nombre.
Nettoyer derrière soi
Il arrive qu'un effect ne se contente pas d'écrire quelque part, mais démarre quelque chose qui continue de vivre : un décompte de temps, une connexion ouverte, une écoute dans une bibliothèque étrangère. Apparaît alors un problème que la seule vigilance ne suffit pas à contourner. Puisque l'effect se réexécute après chaque changement, au dixième changement dix décompteurs tourneraient déjà en même temps, chacun venu d'un passage différent, et aucun ne saurait rien des autres.
C'est pourquoi la fonction d'un effect peut recevoir un paramètre : Angular y place une fonction qui sert à enregistrer le nettoyage. On la nomme par convention onCleanup et tu l'appelles en lui passant ta propre fonction contenant les instructions de rangement. Angular l'exécutera juste avant le passage suivant, ainsi qu'à la fin de vie de l'effect. Dans l'exemple ci-dessous, un veilleur répète chaque seconde son rapport sur le nombre de patrouilles. Pour mesurer le temps, j'utilise la fonction du navigateur setInterval, qui appelle la fonction donnée toutes les tant de millisecondes et renvoie une poignée vers elle-même, ainsi que clearInterval, qui éteint cette poignée. Remarque bien que je lis le nombre de patrouilles avant de lancer le décompte et que je le range dans une constante ordinaire.
1effect((onCleanup) => {
2 const current = this.patrols();
3 const timer = setInterval(() => console.log('Patrouilles sur la route :', current), 1000);
4
5 onCleanup(() => clearInterval(timer));
6});Suivons le cycle entier dans l'ordre, car c'est l'un de ces enchaînements qu'il vaut la peine de savoir réciter, et je l'ai vérifié pas à pas sur un effect en fonctionnement. D'abord l'effect lit un signal et l'enregistre comme dépendance - cela se produit à la ligne du this.patrols(). Ensuite il exécute l'effet de bord proprement dit, à savoir setInterval, et déclare au passage comment on devra ranger après lui. Puis quelqu'un envoie une patrouille de plus et le changement du signal déclenche une nouvelle exécution de l'effect. Et c'est seulement alors, comme toute première opération de ce nouveau passage, que la fonction d'onCleanup s'exécute et éteint la ressource précédente par l'appel clearInterval, juste avant que le corps de l'effect ne reparte avec le nombre à jour. Dans le journal, cela se lit comme une bande : corps pour le premier état, nettoyage du premier état, corps pour le deuxième état, nettoyage du deuxième état, corps pour le troisième état. Jamais deux décompteurs à la fois - je l'ai compté sur du code qui tourne, et il n'y a jamais plus d'un intervalle actif.
Rien n'a changé au passage dans la façon dont fonctionne le signal lui-même, ni dans le nombre de passages de l'effect : le nettoyage n'est pas une exécution supplémentaire et il ne déclenche rien de sa propre initiative. Fais encore attention à cette constante current. Si j'ai lu le signal tout de suite dans le corps de l'effect, c'est justement parce que, comme tu le sais depuis la section précédente, une lecture faite plus tard, à l'intérieur du setInterval, ne deviendrait pas une dépendance : l'effect ne se renouvellerait jamais et le veilleur répéterait son premier rapport jusqu'à la fin des temps.
Quand un effect prend fin
Puisqu'un effect une fois posé travaille en boucle, la question de savoir qui l'éteint finalement vient naturellement. La réponse est plus confortable que tu ne le crains : personne, car Angular s'en charge tout seul. Un effect créé dans le constructeur ou dans l'initialiseur d'un champ se rattache à la vie de ce composant et disparaît avec lui. Je l'ai vérifié sur un composant en fonctionnement : après sa destruction, j'ai encore envoyé deux patrouilles et pas une seule nouvelle entrée n'est apparue dans le registre, alors que le code ne contenait pas une ligne consacrée au rangement.
Cela mérite d'être retenu à part, car dans les vieux exemples que l'on trouve en ligne tu croiseras des composants qui surveillent à la main la destruction de leur effect à l'aide de DestroyRef. Une telle écriture n'est pas fausse, mais elle est superflue : elle répète ce qu'Angular fera de toute façon, et elle enseigne au débutant le réflexe d'écrire des rituels sans nécessité. La documentation d'Angular 19 le dit sans détour à propos de l'option manualCleanup : si tu ne la fournis pas, l'effect s'inscrit lui-même au nettoyage.
Il arrive pourtant que tu veuilles le faire taire plus tôt, du vivant du composant - par exemple lorsque l'élève ferme le registre et que les entrées suivantes ne sont plus que du bruit. C'est à cela que sert la poignée renvoyée par l'appel effect() lui-même. Dans la documentation d'Angular, son type s'appelle EffectRef, et la seule chose qu'il sache faire est la méthode destroy(), sans aucun argument.
1export class PatrolLogComponent {
2 patrols = signal(0);
3
4 private logRef = effect(() => console.log('Patrouilles sur la route :', this.patrols()));
5
6 closeChronicle(): void {
7 this.logRef.destroy();
8 }
9}L'effect siège ici dans l'initialiseur d'un champ et non dans le constructeur, et c'est parfaitement autorisé : un initialiseur de champ est lui aussi un contexte d'injection. Après un appel à closeChronicle(), le chroniqueur se tait pour de bon. Je l'ai vérifié sur un effect en fonctionnement : après destroy(), aucun changement ultérieur du signal ne déclenche plus le corps, et le nettoyage enregistré s'exécute une dernière fois au moment même de la destruction. Et rien d'autre ne change absolument : le signal patrols reste inscriptible et lisible, le template continue d'afficher le nombre à jour, et les autres effects qui regardent cette même tour travaillent sans être dérangés. C'est un registre qu'on a fermé, pas la tour.
Une option que tu croiseras dans du code ancien
Un effect accepte encore un second argument, facultatif : un objet d'options. Dans du code écrit il y a quelques années, tu y rencontreras le plus souvent une seule entrée, allowSignalWrites, et il vaut mieux savoir ce qu'elle signifie avant de la recopier dans ton propre projet.
1effect(() => {
2 // ici le corps de l'effect
3}, { allowSignalWrites: true });L'histoire est courte. Dans Angular 16, 17 et 18, l'écriture dans un signal depuis l'intérieur d'un effect était interdite par défaut et provoquait une erreur ; cette option était le portillon qu'il fallait ouvrir en conscience. Depuis Angular 19, celui sur lequel tu travailles, l'écriture est toujours autorisée et l'option elle-même a été marquée comme obsolète, avec une annotation qui dit sans ambiguïté qu'elle n'est plus nécessaire. J'ai regardé le fichier de types d'Angular 19 : le champ y figure encore, le code compile donc, mais il ne fait plus rien. Ne l'ajoute pas à du code neuf et lorsque tu tomberas dessus dans le projet d'un autre, prends-le pour un avertissement : quelqu'un écrivait là dans des signaux depuis un effect, et cela veut presque toujours dire qu'il voulait en réalité une valeur dérivée.
Là où un effect est à sa place
Maintenant que tu sais ce qu'un effect n'est pas, regardons une tâche taillée exactement pour lui - et justement celle sur laquelle on comprend le plus facilement pourquoi il existe. L'élève choisit un thème d'interface, clair ou sombre. Le choix doit survivre à la fermeture de l'onglet, il faut donc le déposer dans la mémoire du navigateur. C'est le rôle de localStorage et de sa méthode setItem, qui prend deux chaînes de caractères : la clé sous laquelle on range quelque chose, et la valeur. Voilà du code étranger à Angular, purement navigateur et des plus ordinaires - et c'est précisément pour cela que c'est un travail d'effect et non de valeur dérivée.
1import { Component, signal, effect } from '@angular/core';
2
3@Component({
4 selector: 'app-theme',
5 standalone: true,
6 template: '<button (click)="toggleTheme()">Changer de theme</button>'
7})
8export class ThemeComponent {
9 theme = signal('light');
10
11 constructor() {
12 effect(() => {
13 localStorage.setItem('theme', this.theme());
14 });
15 }
16
17 toggleTheme(): void {
18 this.theme.update(t => t === 'light' ? 'dark' : 'light');
19 }
20}J'ai exécuté ce composant et le comportement est exactement celui que tu attends. Juste après le premier affichage, la chaîne "light" repose déjà dans la mémoire du navigateur, parce que l'effect s'est exécuté une fois de lui-même. Après le premier clic on y trouve "dark", après le deuxième de nouveau "light" - la méthode toggleTheme() bascule la valeur du signal, et le chroniqueur la dépose dans le rangement du navigateur sans qu'on le lui demande. Remarque encore une fois ce qui n'a pas bougé : theme est un signal inscriptible ordinaire, toggleTheme() utilise update() de la leçon précédente et ne dit pas un mot de la mémoire du navigateur, et le template lit le thème comme n'importe quelle autre valeur. Si demain tu décidais de l'enregistrer sur un serveur plutôt que dans le navigateur, tu changerais une ligne dans l'effect et rien d'autre.
À quoi un effect sert-il encore ? À tout ce qui est une action et non une valeur, et qui doit se produire après un changement d'état. À tenir un journal et enregistrer les changements, comme notre chroniqueur. À synchroniser un état avec la mémoire du navigateur, comme à l'instant. À appeler une API extérieure, quand le changement doit sortir de l'application. Et à travailler avec des bibliothèques qui ne savent rien d'Angular - une carte, un graphique, un éditeur de texte - car une telle bibliothèque, il faut simplement l'appeler et lui dire que les données ont changé.
Ce qu'un effect ne fait pas
Plusieurs descriptions circulent autour des effects ; elles sonnent crédible et elles sont fausses. Puisque tu connais désormais la mécanique, démolissons-les une par une, car se tromper ici donne du code qui se comporte étrangement sans qu'on sache pourquoi.
Un effect ne crée pas d'animations. Pour animer, Angular dispose d'un paquet séparé, et les transitions les plus simples se font de toute façon en CSS. Un effect ne connaît pas le template, il ne connaît pas les éléments de la page et il n'est capable de rien mettre en mouvement : il appelle uniquement la fonction que tu lui as toi-même donnée. Tu pourrais bien sûr, dans cette fonction, appeler une bibliothèque d'animation étrangère, mais alors c'est elle qui anime, et l'effect n'est qu'un messager annonçant que quelque chose a changé.
Un effect ne combine pas plusieurs signals. Nous en avons parlé à propos du scribe : combiner signifie calculer une valeur à partir de plusieurs autres, et les valeurs, c'est computed() qui les renvoie. La fonction d'un effect n'a aucun moyen de rendre un résultat, puisque personne ne l'attend.
Un effect n'optimise pas le rendu. Dans ce module, la performance vient de tout autre chose : du fait qu'un signal annonce lui-même son changement, si bien qu'Angular ne rafraîchit que les fragments de vue qui l'ont lu, au lieu de faire le tour de tous les châteaux l'un après l'autre. Un effect n'accélère rien là-dedans - au contraire, chaque effect ajouté est une fonction de plus à exécuter après un changement. C'est un outil pour faire des choses, pas pour les faire plus vite.
Un effect ne rend pas de listes ni quoi que ce soit d'autre à l'écran. L'affichage est l'affaire du template, et pour parcourir une collection tu y disposes de la boucle @for avec son track obligatoire, rencontrée dans le module sur les composants. Un effect n'a pas accès à la vue et ne sait pas ajouter un seul caractère à la page.
Et pour finir, le point le plus important dans les grosses applications : un effect n'est pas l'endroit où loger une logique métier complexe. La tentation existe, puisqu'il se déclenche tout seul, mais il possède trois traits qui coûtent cher dans du code sérieux. Il ne renvoie pas de résultat, on ne peut donc pas l'appeler dans un test pour vérifier ce qu'il a calculé. Il s'exécute au moment choisi par Angular et non par toi, l'ordre des événements t'échappe donc. Et il est attaché à la vie du composant, si bien que la logique enfermée dedans disparaît avec l'écran. Les règles du domaine et les opérations partagées habitent dans un service, c'est-à-dire dans la guilde du module précédent - garde l'effect pour les rapports envoyés vers l'extérieur.
Retiens ceci : le scribe calcule et affiche son résultat sur l'ardoise, tandis que le chroniqueur ne calcule rien du tout - il franchit la porte et inscrit dans son registre que la fumée a changé.
Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. À quoi sert effect() dans les Signals d'Angular ?
2. Quelle tâche est un bon usage d'effect() ?
Tâches pratiques dans le jeu
- Tri vertical
Ordonne les étapes d'un effect qui nettoie une ressource (par exemple setInterval).
- Éditeur de code
Complète le composant pour qu'il enregistre le thème dans localStorage à chaque changement.
- Clique dans l'ordre
Ordonne l'appel effect qui affiche la valeur du signal count dans la console.