Faites circuler des données sans prop drilling grâce au contexte, en maîtrisant ses re-rendus et ses limites.
Ouvrir cette leçon dans KodokonLe prop drilling désigne ces props qui traversent trois ou quatre composants intermédiaires sans y être utilisées, juste pour atteindre une feuille de l'arbre. Chaque couche traversée se couple à une donnée qui ne la concerne pas. Le contexte règle ce problème de transport : createContext crée le canal, un provider publie une valeur, et useContext la lit depuis n'importe quel descendant. Gardez la nuance en tête : le contexte transporte de l'état, il n'en gère pas - la valeur vit toujours dans un composant, ici le provider.
import { createContext, useMemo, useState } from "react";
const ThemeContext = createContext(null);
function ThemeProvider({ children }) {
const [theme, setTheme] = useState("dark");
const value = useMemo(
() => ({ theme, setTheme }),
[theme]
);
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
);
}Quand la valeur du provider change, tous les consommateurs re-rendent, même profondément imbriqués - et React.memo ne les protège pas, car il compare des props, pas le contexte. Le piège classique aggrave les choses : écrire value={{ theme, setTheme }} crée un objet neuf à chaque rendu du provider, donc une nouvelle référence, donc des re-rendus en cascade même quand theme n'a pas bougé. C'est le rôle du useMemo ci-dessus. Complétez le dispositif par un hook d'accès qui échoue explicitement hors du provider.
import { useContext } from "react";
function useTheme() {
const context = useContext(ThemeContext);
if (context === null) {
throw new Error(
"useTheme must be inside <ThemeProvider>"
);
}
return context;
}Avant de créer un contexte, épuisez la piste de la composition. Si une couche intermédiaire ne fait que relayer une prop, inversez la structure : construisez l'élément en haut de l'arbre, là où la donnée existe, et passez-le via children ou une prop dédiée. La couche intermédiaire devient générique et la donnée ne traverse plus aucun composant qui ne l'utilise pas.
function App({ currentUser }) {
return (
<Layout
header={<TopBar user={currentUser} />}
content={<Dashboard />}
/>
);
}