Retour • 28/11/2024
Apprendre tous les hooks en React
Écris par Melvyn Malherbe le 28/11/2024
Tu souhaites apprendre tous les hooks en React ? Ou plutôt tous les voir pour mieux comprendre comment ils fonctionnent ? Dans cet article, je vais t'expliquer chaque hook React avec un exemple concret pour m'assurer que tu les comprennes !
useState
Le hook useState
te permet de stocker le state d'un composant. Le state est particulier car chaque fois qu'il change, il provoque un "re-render" qui signifie "le composant est recalculé par React pour connaître le nouveau rendu" afin de pouvoir afficher la nouvelle valeur.
On l'utilise comme ça :
// 👇 getter 👇 setter 👇 valeur initiale
const [count, setCount] = useState(0);
Voici un exemple concret :
Ce qu'il se passe quand le state change :
- Le composant est re-render
- React récupère le JSX qui est retourné
- Il regarde si des éléments ont changé
- Si oui, il les met à jour
- Si non, il ne fait rien
Optimisation avec un initializer
Si ta valeur initiale est coûteuse à calculer (comme un gros tableau ou un calcul complexe), tu peux passer une fonction d'initialisation à useState
:
// ❌ createInitialTodos est appelé à chaque render
const [todos, setTodos] = useState(createInitialTodos());
// ✅ createInitialTodos est appelé uniquement à l'initialisation
const [todos, setTodos] = useState(() => createInitialTodos());
useEffect
Le hook useEffect
te permet d'exécuter du code en réaction à des changements dans ton composant. C'est parfait pour synchroniser ton composant avec des systèmes externes comme une API ou le localStorage.
useEffect(() => {
// Ce code s'exécute après le render
document.title = `Vous avez cliqué ${count} fois`;
}, [count]); // Uniquement si count change
Les cas d'utilisation principaux :
- Synchronisation avec des APIs externes
- Souscription à des événements
- Mise à jour du DOM manuellement
- Logging
- Chargement de données
Les pièges à éviter
- Ne pas mettre de dépendances dans le tableau quand il en faut
- Mettre trop de dépendances et créer des boucles infinies
- Oublier de nettoyer (cleanup) les effets qui en ont besoin
Voici un exemple correct avec cleanup :
useEffect(() => {
const subscription = api.subscribe(data => {
// Faire quelque chose avec data
});
// Cleanup : se désabonner quand le composant est démonté
return () => {
subscription.unsubscribe();
};
}, []);
useContext
Le hook useContext
te permet d'accéder à des valeurs partagées dans ton arbre de composants sans avoir à passer les props manuellement à chaque niveau.
// 1. Créer le contexte
const ThemeContext = createContext('light');
// 2. Fournir une valeur
function App() {
return (
<ThemeContext.Provider value="dark">
<Button />
</ThemeContext.Provider>
);
}
// 3. Consommer la valeur
function Button() {
const theme = useContext(ThemeContext);
return <button className={theme}>Je suis {theme}</button>;
}
Voici un exemple :
useRef
Le hook useRef
te permet de garder une référence mutable qui persiste entre les renders. C'est très utile pour :
- Stocker des références DOM
- Garder des valeurs qui ne déclenchent pas de re-render
- Stocker des valeurs précédentes
function TextInputWithFocusButton() {
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} type="text" />
<button onClick={handleClick}>Focus l'input</button>
</>
);
}
Exemple complet :
useMemo et useCallback
Ces hooks sont utilisés pour l'optimisation des performances :
useMemo
mémorise le résultat d'un calcul coûteuxuseCallback
mémorise une fonction
// Mémoiser un calcul coûteux
const memoizedValue = useMemo(() => {
return computeExpensiveValue(a, b);
}, [a, b]);
// Mémoiser une fonction
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
Exemple complet :
useReducer
Pour des states plus complexes, useReducer
te permet de gérer les mises à jour de state avec un pattern similaire à Redux :
const [state, dispatch] = useReducer(reducer, initialState);
// Dans ton reducer
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
Exemple complet :
useActionState
Le hook useActionState
est un nouveau hook disponible dans la version Canary de React qui te permet de gérer l'état d'un formulaire en fonction du résultat d'une action.
const [state, formAction, isPending] = useActionState(fn, initialState);
C'est particulièrement utile pour :
- Gérer les états de formulaire
- Afficher des messages d'erreur
- Mettre à jour l'UI en fonction du résultat d'une action
Exemple concret :
import { useActionState } from "react";
async function increment(previousState, formData) {
return previousState + 1;
}
function Counter() {
const [count, formAction] = useActionState(increment, 0);
return (
<form>
<p>Compteur: {count}</p>
<button formAction={formAction}>Incrémenter</button>
</form>
);
}
useOptimistic
Le hook useOptimistic
est un nouveau hook qui te permet d'afficher un état optimiste pendant qu'une action est en cours. C'est super utile pour améliorer l'expérience utilisateur en montrant immédiatement le résultat attendu d'une action.
const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);
Voici un exemple avec un bouton "J'aime" :
useInsertionEffect
Le hook useInsertionEffect
est similaire à useEffect
, mais il s'exécute de manière synchrone avant toutes les mutations DOM. Il est principalement destiné aux bibliothèques CSS-in-JS.
useInsertionEffect(setup, dependencies?);
⚠️ Attention
- Ce hook est destiné aux bibliothèques CSS-in-JS, pas à l'utilisation dans des applications normales
- Il s'exécute uniquement côté client
- Il n'a pas accès aux refs
// Exemple d'utilisation dans une bibliothèque CSS-in-JS
useInsertionEffect(() => {
if (!isInserted.current) {
isInserted.current = true;
// Injecter des styles CSS dynamiques ici
}
});
useSyncExternalStore
Le hook useSyncExternalStore
te permet de souscrire à une source de données externe de manière sûre pour la concurrence.
const state = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?);
C'est particulièrement utile pour :
- S'abonner à des stores externes (Redux, MobX, etc.)
- Gérer des événements du navigateur
- Synchroniser avec des APIs externes
Exemple avec le statut en ligne/hors ligne :
Ces nouveaux hooks apportent des fonctionnalités puissantes pour gérer des cas d'usage spécifiques comme l'optimistic UI, la gestion de formulaires serveur et l'intégration avec des systèmes externes. N'hésite pas à les explorer pour améliorer l'expérience utilisateur de tes applications !
Conclusion
Les hooks sont la base de la gestion d'état et des effets de bord dans React. En comprenant bien chacun d'entre eux, tu pourras :
- Créer des composants plus maintenables
- Optimiser les performances quand nécessaire
- Partager de la logique entre composants
- Gérer proprement les effets de bord
N'hésite pas à pratiquer avec chaque hook individuellement avant de les combiner. La pratique est la clé pour bien les maîtriser !