Depuis l'introduction des Hooks dans la version 16.8, la manière de concevoir des composents React a radicalement changé. Ils permettent d'utiliser l'état local et d'auters fonctionnalités de React sans avoir recours aux classes. Cet article explore les Hooks les plus courants ainsi que les outils plus spécialisés pour optimiser vos applications.
Les Hooks de Base et Incontournables
1. useState
Le hook useState est le pilier de la gestion d'état dans les composants fonctionnels. Il déclare une variable d'état qui persiste entre les cycles de rendu.
import React, { useState } from 'react';
function CompteurDeClics() {
const [score, setScore] = useState(0);
return (
<div>
<p>Score actuel : {score}</p>
<button onClick={() => setScore(score + 5)}>Ajouter 5</button>
</div>
);
}
2. useEffect
Ce hook permet de gérer les effets de bord (appels API, abonnements, manipulations manuelles du DOM). Il s'exécute après le rendu du composant.
import React, { useState, useEffect } from 'react';
function ExplorateurUtilisateur({ userId }) {
const [profil, setProfil] = useState(null);
useEffect(() => {
const chargerDonnees = async () => {
const reponse = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
const data = await reponse.json();
setProfil(data);
};
chargerDonnees();
}, [userId]);
if (!profil) return <p>Chargement...</p>;
return <div>Nom : {profil.name}</div>;
}
3. useContext
useContext facilite le partage de données à travers l'arbre des composants sans passer manuellement des props à chaque niveau.
import React, { useContext, createContext } from 'react';
const ConfigContext = createContext({ langue: 'fr' });
function MessageBienvenue() {
const { langue } = useContext(ConfigContext);
return <h1>{langue === 'fr' ? 'Bienvenue' : 'Welcome'}</h1>;
}
4. useReducer
Idéal pour les logiques d'état complexes impliquant plusieurs sous-valeurs ou lorsque l'état suivant dépend du précédent.
import React, { useReducer } from 'react';
const gestionStock = (etat, action) => {
switch (action.type) {
case 'AJOUT': return { total: etat.total + 1 };
case 'RETRAIT': return { total: etat.total - 1 };
default: return etat;
}
};
function Inventaire() {
const [etat, dispatch] = useReducer(gestionStock, { total: 0 });
return (
<div>
<span>Articles : {etat.total}</span>
<button onClick={() => dispatch({ type: 'AJOUT' })}>+</button>
<button onClick={() => dispatch({ type: 'RETRAIT' })}>-</button>
</div>
);
}
Optimisation et Performence
5. useMemo et useCallback
useMemo mémorise une valeur calculée, tandis que useCallback mémorise une instance de fonction pour éviter des rendus inutiles de composants enfants optimisés.
import React, { useState, useMemo, useCallback } from 'react';
function CalculateurPuissance() {
const [nombre, setNombre] = useState(1);
const [themeSombre, setThemeSombre] = useState(false);
const resultatLourd = useMemo(() => {
console.log('Calcul en cours...');
return Math.pow(nombre, 10);
}, [nombre]);
const basculerTheme = useCallback(() => {
setThemeSombre(prev => !prev);
}, []);
return (
<div style={{ background: themeSombre ? '#333' : '#fff' }}>
<input type="number" value={nombre} onChange={e => setNombre(parseInt(e.target.value))} />
<p>Résultat : {resultatLourd}</p>
<button onClick={basculerTheme}>Changer Mode</button>
</div>
);
}
Hooks Spécialisés et Avancés
6. useRef et useImperativeHandle
useRef permet de conserver une référence mutable qui ne déclenche pas de nouveau rendu. Combiné à useImperativeHandle, il permet de personnaliser l'instance exposée par un composant via une ref.
import React, { useRef, useImperativeHandle, forwardRef } from 'react';
const LecteurVideo = forwardRef((props, ref) => {
const videoElement = useRef();
useImperativeHandle(ref, () => ({
lancer: () => videoElement.current.play(),
arreter: () => videoElement.current.pause()
}));
return <video ref={videoElement} src="film.mp4" />;
});
7. useLayoutEffect
Similaire à useEffect, mais il s'exécute de manière synchrone après toutes les mutations du DOM. Il est utile pour lire la mise en page du DOM et effectuer des rendus synchrones.
8. La Gestion de la Concurrence : useTransition et useDeferredValue
Ces hooks permettent de prioriser les mises à jour de l'interface utilisateur. useTransition marque certaines mises à jour d'état comme non-urgentes, tandis que useDeferredValue permet de différer la mise à jour d'une partie de l'UI.
import React, { useState, useTransition } from 'react';
function FiltrageProduits({ liste }) {
const [filtre, setFiltre] = useState('');
const [estEnAttente, demarrerTransition] = useTransition();
const majFiltre = (e) => {
demarrerTransition(() => {
setFiltre(e.target.value);
});
};
return (
<div>
<input type="text" onChange={majFiltre} />
{estEnAttente ? <p>Mise à jour de la liste...</p> : null}
{/* Rendu de la liste filtrée */}
</div>
);
}
9. useSyncExternalStore
Introduit pour résoudre les problèmes de lecture de sources de données externes dans le mode concurrent de React, ce hook est essentiel pour les bibliothèques de gestion d'état comme Redux ou Zustand.