
Introduction à l'API Context (React.createContext, Provider, Consumer)
Découvrez les bases de l'API Context de React (createContext, Provider, Consumer) comme solution au prop drilling pour partager des données globalement.
L'API Context : Une réponse au Prop Drilling
Comme nous l'avons exploré dans la section précédente, le "prop drilling" peut rapidement rendre la transmission de données à travers plusieurs niveaux de composants fastidieuse et difficile à maintenir. Passer des props via des composants intermédiaires qui n'en ont pas besoin alourdit le code et complique le refactoring.
Face à ce défi, React propose une solution intégrée : l'API Context. Elle offre un moyen de faire circuler des données (comme l'état de l'utilisateur authentifié, le thème de l'application, ou la langue préférée) à travers l'arbre des composants sans avoir à passer explicitement les props à chaque niveau. L'idée est de rendre certaines données "globales" pour une partie de l'arbre de composants.
L'API Context repose sur trois éléments fondamentaux que nous allons introduire ici : React.createContext pour initialiser le contexte, le composant Provider pour fournir la valeur, et le composant Consumer (ou le hook `useContext`, que nous verrons ensuite) pour lire cette valeur.
Création d'un Contexte : `React.createContext`
La première étape pour utiliser l'API Context est de créer un objet Contexte. Cela se fait à l'aide de la fonction React.createContext. Cette fonction retourne un objet contenant notamment les composants `Provider` et `Consumer` associés à ce contexte spécifique.
La fonction createContext accepte un argument optionnel : une valeur par défaut. Cette valeur par défaut sera utilisée par un composant `Consumer` (ou `useContext`) uniquement s'il ne trouve aucun `Provider` correspondant pour ce contexte dans l'arbre de ses ancêtres.
import React from 'react';
// 1. Création du contexte
// On peut fournir une valeur par défaut (ici, pour un thème)
const ThemeContext = React.createContext('light'); // 'light' est la valeur par défaut
// On peut aussi créer un contexte sans valeur par défaut explicite (undefined par défaut)
const UserContext = React.createContext();
export { ThemeContext, UserContext }; // Exporter pour utilisation ailleurs
Fournir une valeur par défaut peut être utile pour les tests ou pour des scénarios où un composant peut être utilisé en dehors d'un `Provider`, mais il est généralement préférable de s'assurer que chaque composant consommateur est bien enveloppé par un `Provider` approprié.
Fournir la valeur : `Context.Provider`
Une fois le contexte créé (par exemple, `const MonContext = React.createContext(...)`), l'objet retourné contient un composant nommé Provider (accessible via `MonContext.Provider`). Ce composant est utilisé pour "fournir" la valeur du contexte à tous les composants descendants qui souhaiteront la consommer.
Le composant `Provider` accepte une prop obligatoire : value. C'est la valeur que tous les composants `Consumer` (ou `useContext`) descendants liront. Vous enveloppez la partie de votre arbre de composants qui a besoin d'accéder à cette valeur avec le `Provider`.
import React, { useState } from 'react';
import { ThemeContext, UserContext } from './contexts'; // Importe les contextes créés
import Toolbar from './Toolbar';
function App() {
const [theme, setTheme] = useState('dark');
const [user, setUser] = useState({ name: 'Alice' });
// Fonction pour changer le thème (exemple)
const toggleTheme = () => setTheme(prev => (prev === 'light' ? 'dark' : 'light'));
// Enveloppe les composants nécessitant le thème avec ThemeContext.Provider
// et ceux nécessitant l'utilisateur avec UserContext.Provider
return (
{/* Toolbar et ses enfants auront accès aux contextes */}
);
}
export default App;
Tous les descendants du `Provider` peuvent accéder à la valeur fournie, peu importe leur profondeur. Si vous imbriquez plusieurs `Provider` pour le *même* contexte, les descendants liront la valeur du `Provider` le plus proche dans l'arbre au-dessus d'eux. Lorsque la prop `value` du `Provider` change, tous les composants descendants qui consomment ce contexte seront re-rendus.
Consommer la valeur : `Context.Consumer` (Approche historique)
Avant l'introduction des Hooks, la manière standard de consommer une valeur de contexte dans un composant (qu'il soit de classe ou fonctionnel) était d'utiliser le composant Consumer (accessible via `MonContext.Consumer`).
Le composant `Consumer` utilise un pattern appelé "Render Prop". Il attend une fonction comme enfant (children). Cette fonction reçoit la valeur actuelle du contexte (celle fournie par le `Provider` le plus proche) comme argument et doit retourner un élément React (du JSX). C'est à l'intérieur de cette fonction que vous avez accès à la valeur du contexte.
import React from 'react';
import { ThemeContext, UserContext } from './contexts';
// Exemple d'un composant qui consomme les deux contextes via Consumer
function Button() {
return (
{theme => ( // Fonction enfant pour ThemeContext
{user => ( // Fonction enfant pour UserContext
)}
)}
);
}
// Ce composant Button doit être rendu quelque part à l'intérieur
// des Providers définis dans App.js pour fonctionner correctement.
export default Button;
Bien que fonctionnelle, cette approche avec `
Résumé des concepts de base
L'API Context fournit donc un mécanisme en trois étapes pour partager des données sans prop drilling :
React.createContext(defaultValue): Crée un objet Contexte.MyContext.Provider value={someValue}: Enveloppe une partie de l'arbre et rendsomeValuedisponible à tous les descendants.MyContext.Consumer>{value => /* JSX utilisant value */}: Permet à un composant descendant de s'abonner aux changements du contexte et d'accéder àvaluevia une fonction enfant (Render Prop).
Cette API est particulièrement adaptée pour des données considérées comme "globales" pour une partie significative de l'arbre de composants, telles que les informations d'authentification, les préférences de thème, la localisation, etc. Elle constitue une alternative directe et intégrée à React pour éviter le prop drilling excessif.
Maintenant que nous avons compris les composants fondamentaux `Provider` et `Consumer`, explorons le hook `useContext` qui simplifie grandement la consommation de contexte dans les composants fonctionnels modernes.