
Règles des hooks et linters
Comprenez les deux règles fondamentales des Hooks React et pourquoi l'utilisation du plugin ESLint (eslint-plugin-react-hooks) est essentielle pour les appliquer.
Introduction : Pourquoi des règles spécifiques aux Hooks ?
Les Hooks React (comme useState, useEffect, useContext, etc., ainsi que vos propres Hooks personnalisés) reposent sur un mécanisme interne qui dépend de l'ordre dans lequel ils sont appelés à chaque rendu. Pour que React puisse associer correctement l'état et les effets à la bonne instance de Hook entre les différents rendus d'un composant, il est impératif que l'ordre d'appel des Hooks reste constant à chaque fois que le composant est rendu.
Pour garantir ce comportement stable et prévisible, React impose deux règles strictes sur la manière dont les Hooks doivent être utilisés. Le non-respect de ces règles peut entraîner des bugs subtils et difficiles à déboguer, où l'état semble se mélanger entre différents Hooks ou où les effets ne se comportent pas comme prévu.
Règle n°1 : Appeler les Hooks uniquement au Niveau Supérieur
La règle : N'appelez jamais les Hooks à l'intérieur de boucles (for, while), de conditions (if, switch), ou de fonctions JavaScript imbriquées (fonctions définies à l'intérieur de votre composant ou de votre Hook personnalisé).
Pourquoi ? React s'appuie sur l'ordre d'appel des Hooks pour associer l'état et les effets à chaque Hook. Si vous placez un appel de Hook dans une condition, cet appel pourrait être sauté lors de certains rendus mais pas d'autres. Cela changerait l'ordre des appels de Hooks suivants, et React ne saurait plus quel état correspond à quel appel de useState ou quel effet correspond à quel appel de useEffect.
Exemple Incorrect :
function MonComposant({ doitAfficherNom }) {
// Appel de useState au niveau supérieur (Correct)
const [count, setCount] = useState(0);
if (doitAfficherNom) {
// !!! INCORRECT : useState appelé dans une condition !!!
const [name, setName] = useState('Alice');
// L'ordre des hooks changerait si doitAfficherNom passe de true à false
}
// Appel de useEffect au niveau supérieur (Correct)
useEffect(() => {
// ...
});
// ...
}
Solution Correcte :
Si vous avez besoin d'exécuter une logique de Hook conditionnellement, déplacez la condition à l'intérieur du Hook si possible, ou appelez toujours le Hook et gérez la condition dans sa logique interne ou son retour.
function MonComposant({ doitAfficherNom }) {
const [count, setCount] = useState(0);
// Appeler le Hook au niveau supérieur
const [name, setName] = useState('Alice');
useEffect(() => {
// La condition est DANS l'effet
if (doitAfficherNom) {
console.log('Le nom est affiché:', name);
}
}, [name, doitAfficherNom]);
return (
Compteur: {count}
{/* Condition pour l'affichage, pas pour l'appel du Hook */}
{doitAfficherNom && Nom: {name}
}
);
}
Règle n°2 : Appeler les Hooks uniquement depuis des Fonctions React
La règle : N'appelez les Hooks que depuis deux endroits :
- Les composants fonctionnels React : Directement à l'intérieur du corps de votre fonction composant.
- Les Hooks personnalisés : A l'intérieur de vos propres fonctions dont le nom commence par
use.
Pourquoi ? Les Hooks ont besoin du contexte d'un composant React en cours de rendu pour pouvoir stocker leur état et leurs effets. Les appeler depuis une fonction JavaScript classique, un gestionnaire d'événement hors du rendu, ou un composant de classe ne fonctionnera pas car ce contexte n'existera pas.
Exemples Incorrects :
// !!! INCORRECT : Appel depuis une fonction JS classique !!!
function utilitaireNormal() {
const [valeur, setValeur] = useState(0); // Erreur : Hook appelé hors d'un composant/hook
}
// !!! INCORRECT : Appel depuis un composant de classe !!!
class MonComposantClasse extends React.Component {
render() {
// const [valeur, setValeur] = useState(0); // Erreur
return ...;
}
}
function MonComposantFonctionnel() {
const handleClick = () => {
// !!! INCORRECT : Appel depuis un gestionnaire d'événement !!!
// (la logique stateful doit être DANS le corps du composant, pas ici)
// useEffect(() => { /* ... */ });
}
return ;
}
L'aide indispensable : Le Linter ESLint
Mémoriser et appliquer manuellement ces règles peut être fastidieux et source d'erreurs. Heureusement, l'équipe React fournit un plugin ESLint officiel pour vous aider : eslint-plugin-react-hooks.
Ce plugin contient deux règles essentielles :
react-hooks/rules-of-hooks: Vérifie que vous respectez les deux règles fondamentales décrites ci-dessus (appel au niveau supérieur, appel depuis des fonctions React).react-hooks/exhaustive-deps: Vérifie que vous avez bien inclus toutes les dépendances nécessaires dans le tableau de dépendances des hooks commeuseEffect,useCallback,useMemo. Elle vous avertit si des dépendances sont manquantes (source fréquente de bugs) et propose souvent des corrections automatiques.
Il est fortement recommandé d'installer et de configurer ce plugin dans votre projet React. La plupart des outils de création de projets modernes (comme Create React App, Vite avec template React) l'incluent et le configurent par défaut.
Activer ce linter dans votre éditeur de code vous fournira un retour immédiat si vous enfreignez l'une des règles, vous aidant à écrire du code Hooks correct et robuste dès le départ.
Conclusion : Des règles pour la stabilité
Les deux règles des Hooks ne sont pas des suggestions, mais des exigences fondamentales pour garantir le bon fonctionnement du mécanisme interne des Hooks dans React. En les respectant (appel au niveau supérieur uniquement, et uniquement depuis des fonctions React), vous assurez la stabilité et la prévisibilité de l'état et des effets de vos composants.
L'utilisation systématique du plugin ESLint eslint-plugin-react-hooks est le meilleur moyen de garantir le respect de ces règles sans effort conscient constant, vous permettant de vous concentrer sur la logique de votre application tout en bénéficiant de la puissance et de la flexibilité des Hooks.