Règles des Hooks
Les principes stricts pour utiliser les Hooks
Le concept : Les Hooks sont extrêmement puissants, mais pour que React puisse lier correctement la mémoire (le state) à chaque composant entre les rendus successifs, il s'appuie strictement sur l'ordre d'appel de ces hooks.
C'est pourquoi vous ne devez jamais appeler un hook à l'intérieur d'une condition (if), d'une boucle (for) ou d'une fonction imbriquée. L'ordre doit rester identique à chaque cycle de rendu.
💡 La "Magie" des Hooks
React ne scanne pas votre code pour trouver les Hooks. Il compte simplement l'ordre d'appel.
"Au premier rendu, le 1er Hook est un useState(0). Le 2ème est un useEffect..."
Si vous mettez un Hook dans un if, l'ordre des appels change au rendu
suivant, et
React perd le fil ("Attends, le 2ème Hook était un useEffect, pourquoi c'est un useState
maintenant ?"). C'est pour ça que l'ordre doit être stable.
1. Top Level Uniquement
Ne jamais appeler un Hook dans une boucle, une condition ou une fonction imbriquée.
2. React Functions Uniquement
Appeler les Hooks seulement depuis des composants React ou des Custom Hooks.
3. Nommage
Les Custom Hooks doivent toujours commencer par use... (ex:
useAuth).
// En interne, React stocke les Hooks dans un tableau (Linked List) // Rendu N°1 [0] useState("Alice") // Nom [1] useEffect(...) // Document Title [2] useState("Blue") // Thème // Si vous mettez une condition sur le useEffect et qu'elle passe à false... // Rendu N°2 (BUG) [0] useState("Alice") // OK [1] useState("Blue") // ERREUR ! React pense que c'est le useEffect.
Ne comptez pas sur votre vigilance. Installez le plugin ESLint officiel :
npm install eslint-plugin-react-hooks --save-dev
🎧 Analogie : La Playlist Musicale (Mental Model)
Imaginez que React conserve les valeurs (State) de vos hooks dans une liste, comme une playlist MP3 :
- 1. 🎵
useState('Alice')(Piste 1) - 2. 🎵
useEffect(...)(Piste 2) - 3. 🎵
useState('Dark')(Piste 3)
Si au rendu suivant, vous mettez une condition et sautez la piste 2...
React va jouer la piste 3 (Theme) en pensant que c'est la piste 2 (Effect). Tout se décalle ! 💥
// Rendu 1 (Normal) [0] "Alice" [1] Effect [2] "Dark" // Rendu 2 (Avec condition if(false) sur le Hook 2) [0] "Alice" [1] "Dark" // ⚠️ React essaye de lire un State comme un Effect ! [2] undefined // Perdu dans les limbes
🛡️ Le garde du corps : ESLint
Le plugin eslint-plugin-react-hooks est votre meilleur ami. Il vérifie deux
choses :
- Rules of Hooks : Vérifie que vous n'appelez pas de hooks dans des conditions.
- Exhaustive Deps : Vérifie que le tableau de dépendances de
useEffectouuseMemoest complet.
Ne désactivez jamais cette règle (// eslint-disable-line)
sauf si vous savez EXACTEMENT ce que vous faites (et encore...).
// Si vous voulez RAZ un composant (et tous ses hooks) // Changez sa prop "key" ! <UserProfile key={ userId } /> // Si userId change, React détruit l'ancien composant // et en recrée un neuf (State à 0).