useEffect et nettoyage
Lancer une minuterie quand le composant apparaît, et surtout l'arrêter quand il disparaît.
Objectifs de la séance
- comprendre ce qu'est un effet et quand
useEffects'exécute ; - maîtriser le tableau de dépendances (
[],[valeur], absent) ; - écrire la fonction de nettoyage (
return () => ...) ; - observer ce que fait StrictMode et ce qui se passe sans nettoyage ;
- mettre à jour le titre de l'onglet du navigateur.
Petite vérification
Avant de commencer, vérifiez si vous savez...
- jouer une partie et vérifier que le double clic sur une réponse n'ajoute qu'un point
- ouvrir
src/logic/partieReducer.tset citer les deux types d'action possibles - dire ce que renvoie le reducer lorsqu'on envoie
SUIVANTEalors que le statut est"question"
📌 Réponse attendue
Notions théoriques
Qu'est-ce qu'un effet ?
Le corps d'un composant doit rester pur : il calcule le JSX à afficher à partir de l'état et des props, sans rien faire d'autre. Tout ce qui touche à l'extérieur (minuterie, réseau, titre de la page, abonnement) est un effet, et se place dans useEffect. Il s'exécute après l'affichage.
import { useEffect } from "react";
useEffect(() => {
console.log("Le composant vient d'être affiché");
}, []);
Le tableau de dépendances
Le deuxième argument indique quand l'effet s'exécute :
| Écriture | L'effet s'exécute... |
|---|---|
useEffect(effet, []) | une seule fois, après le premier affichage |
useEffect(effet, [secondes]) | après le premier affichage, puis chaque fois que secondes change |
useEffect(effet) (sans tableau) | après chaque affichage (presque toujours une erreur) |
Règle : le tableau liste toutes les variables (états, props) utilisées par l'effet. Sinon, l'effet travaille avec une valeur périmée (c'est le piège des fermetures vu dans le cours JavaScript). L'outil npm run lint signale les dépendances oubliées.
La fonction de nettoyage
Un effet peut renvoyer une fonction : c'est son nettoyage. React l'exécute :
- avant de relancer l'effet (quand une dépendance change) ;
- quand le composant disparaît de l'écran.
import { useEffect, useState } from "react";
import { formaterDuree } from "../logic/duree";
export function Chronometre() {
const [secondes, setSecondes] = useState(0);
useEffect(() => {
const minuterie = setInterval(() => {
setSecondes((ancien) => ancien + 1);
}, 1000);
return () => {
clearInterval(minuterie);
};
}, []);
return <p>Temps : {formaterDuree(secondes)}</p>;
}
Remarquez la mise à jour fonctionnelle setSecondes((ancien) => ancien + 1) : la minuterie est créée une seule fois, avec la première valeur de secondes. Écrire setSecondes(secondes + 1) ajouterait toujours 1 à 0 : la valeur périmée !
Chaque fois qu'un effet démarre quelque chose (minuterie, requête, abonnement), demandez-vous : « qui l'arrête ? ». La réponse est la fonction de nettoyage.
Pourquoi le nettoyage est indispensable
Quand la partie se termine, Chronometre disparaît de l'écran. Sans nettoyage, la minuterie continuerait à tourner, à mettre à jour un composant qui n'existe plus, et à consommer de la mémoire. À chaque nouvelle partie, une minuterie supplémentaire s'ajouterait.
StrictMode : le détecteur de nettoyages oubliés
En développement, StrictMode (dans main.tsx) exécute chaque effet deux fois au démarrage : lancement, nettoyage, relancement. Si votre nettoyage est correct, vous ne voyez aucune différence. S'il manque :
- la minuterie est lancée deux fois, la première n'est jamais arrêtée ;
- le chronomètre avance deux fois trop vite ! (essayez en supprimant le
return () => ...: le compteur passe de 2 en 2.)
C'est un excellent détecteur : un bug caché en production devient visible pendant le développement.
Un deuxième effet : le titre de l'onglet
Plusieurs effets peuvent coexister dans un même composant, chacun avec son rôle et ses dépendances.
useEffect(() => {
document.title = `Quiz Cyber (${formaterDuree(secondes)})`;
return () => {
document.title = "Quiz Cyber"; // on restaure le titre d'origine
};
}, [secondes]);
Cet effet s'exécute à chaque changement de secondes (donc chaque seconde), et son nettoyage restaure le titre quand le composant disparaît.
Quand ne PAS utiliser un effet
- réagir à un clic : le code va dans la fonction appelée par
onClick, pas dans un effet ; - calculer une valeur à partir de l'état (un pourcentage, une liste filtrée) : calculez-la directement pendant le rendu, sans effet ni état supplémentaire.
Un effet sert uniquement à synchroniser le composant avec le monde extérieur.
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Votre mission : ajouter un chronomètre à la partie, avec le titre de l'onglet synchronisé.