useContext : essence, le hook d'accès au contexte et les fournisseurs dans React

Auteur : IT Sectr Publié le : 2026-07-04 Temps de lecture : 9 min

useContext est un hook React qui offre aux composants fonctionnels un accès direct aux données d'un contexte créé via createContext. Le contexte dans React résout le problème du props drilling — la transmission de props à travers de nombreux composants intermédiaires qui n'utilisent pas ces données eux-mêmes. Selon la React Documentation (2025), useContext reçoit un objet de contexte et retourne la valeur actuelle définie par le Provider le plus proche dans l'arborescence des composants. Lorsque la valeur dans le Provider change, tous les composants utilisant useContext sont automatiquement restitués.

Points clés

  • useContext — hook pour lire une valeur du contexte React sans props drilling.
  • createContext — crée un objet de contexte avec une valeur par défaut et un composant Provider.
  • Provider — composant wrapper qui transmet la valeur du contexte à tous les éléments enfants.
  • Re-rendu — la modification de la valeur du Provider provoque le re-rendu de tous les consommateurs du contexte.
  • Saut des composants intermédiaires — useContext permet de transmettre des données à travers plusieurs niveaux d'imbrication.

Qu'est-ce que useContext dans React

useContext est un hook ajouté dans React 16.8 avec les autres hooks qui permet de lire une valeur à partir du contexte React. Le contexte est un mécanisme intégré dans React conçu pour transmettre des données à travers l'arborescence des composants sans avoir à passer manuellement des props à chaque niveau. useContext remplace le composant Consumer de l'ancienne Context API et rend le code plus concis et lisible.

Les cas d'utilisation typiques du contexte incluent les thèmes (clair/sombre), les paramètres régionaux et les traductions (i18n), l'authentification utilisateur, les paramètres de l'application et toutes autres données globales dont de nombreux composants à différents niveaux d'imbrication ont besoin. L'équipe React recommande d'utiliser le contexte pour les données qui sont globales pour une sous-arborescence de composants, mais pas pour l'ensemble de l'application.

Selon la React Team — Documentation du contexte (2025), une mauvaise utilisation du contexte est l'une des principales causes de problèmes de performance dans les applications React. Chaque changement de valeur dans le Provider provoque un re-rendu de tous les consommateurs, indépendamment de la partie des données qui a changé. L'optimisation via useMemo et la division des contextes résout ce problème.

jsx
import { createContext, useContext } from 'react';

// Créer un contexte avec une valeur par défaut
const ThemeContext = createContext('clair');

function ThemedButton() {
    const theme = useContext(ThemeContext);
    return <button className={`btn-${theme}`}>Click</button>;
}

Comment fonctionne le contexte dans React

Le mécanisme de contexte dans React est implémenté via le modèle Provider-Consumer. createContext retourne un objet avec deux entités : Provider — un composant qui transmet la valeur, et l'objet de contexte lui-même, qui est utilisé dans useContext. Le Provider est monté dans l'arborescence des composants et transmet la valeur à tous les éléments enfants quelle que soit la profondeur d'imbrication.

Lorsque React rencontre un appel useContext, il parcourt l'arbre fibre à la recherche du Provider le plus proche pour ce contexte. Si un Provider est trouvé, sa valeur est retournée. Si aucun Provider n'est trouvé, la valeur par défaut passée à createContext est retournée. Cette recherche a lieu à chaque rendu, mais grâce à la mémoïsation des nœuds fibre, elle est très rapide et n'affecte pas les performances.

Selon React — Internes du contexte (2024), l'implémentation interne de useContext utilise une liste chaînée de hooks, similaire à useState. Chaque hook stocke une référence à un nœud fibre, permettant à React de déterminer rapidement quel Provider correspond à ce contexte. Lorsqu'un Provider met à jour sa valeur, React marque tous les nœuds fibre utilisant ce contexte pour un re-rendu.

Provider et contextes imbriqués

Les composants Provider peuvent être imbriqués les uns dans les autres, créant une hiérarchie de contextes. Chaque Provider enfant remplace la valeur du parent pour sa propre sous-arborescence. Ceci est utile lorsqu'un écran a besoin d'un thème clair tandis qu'une fenêtre modale imbriquée a besoin d'un thème sombre. useContext retourne toujours la valeur du Provider le plus proche dans l'arborescence.

jsx
const UserContext = createContext(null);
const ThemeContext = createContext('clair');

function App() {
    return (
        <UserContext.Provider value={{ name: 'Alice' }}>
            <ThemeContext.Provider value='dark'>
                <Profile />
            </ThemeContext.Provider>
        </UserContext.Provider>
    );
}

Création d'un fournisseur avec createContext

La fonction createContext(defaultValue) crée un objet de contexte. Le paramètre defaultValue est utilisé lorsqu'un composant appelle useContext mais qu'aucun Provider correspondant n'est présent dans l'arborescence. Sans defaultValue, useContext retournera undefined, ce qui peut entraîner des erreurs inattendues. Il est recommandé de toujours passer une valeur par défaut significative ou null.

La création d'un fournisseur personnalisé est un modèle courant pour encapsuler la logique du contexte. À l'intérieur d'un tel fournisseur, l'état est stocké (via useState ou useReducer) et fourni via la prop value du Provider. Cela masque les détails d'implémentation aux composants consommateurs et centralise la logique de gestion du contexte en un seul endroit.

jsx
// Fournisseur personnalisé avec gestion d'état
const AuthContext = createContext(null);

function AuthProvider({ children }) {
    const [user, setUser] = useState(null);

    const login = useCallback(async (email, pass) => {
        const u = await loginApi(email, pass);
        setUser(u);
    }, []);

    return (
        <AuthContext.Provider value={{ user, login }}>
            {children}
        </AuthContext.Provider>
    );
}

Utilisation de useContext dans les composants enfants

Dans les composants fonctionnels, useContext est le seul moyen d'accéder au contexte. Il remplace le composant Consumer de l'ancienne Context API, qui nécessitait le modèle render-prop : <ThemeContext.Consumer>{value => ...}</ThemeContext.Consumer>. useContext rend le code plus linéaire et lisible, surtout lorsqu'on travaille avec plusieurs contextes dans un même composant.

Lors de l'utilisation de plusieurs contextes dans un composant, appelez simplement useContext plusieurs fois pour chaque contexte. Chaque appel retourne la valeur du Provider correspondant. L'ordre des appels n'a pas d'importance, car chaque contexte est une entité indépendante. React optimise les appels multiples via le même système de références fibre.

jsx
function Dashboard() {
    const { user } = useContext(AuthContext);
    const theme = useContext(ThemeContext);
    const { locale } = useContext(I18nContext);

    return (
        <div className={`dashboard-${theme}`}>
            <h1>{locale.greeting}, {user.name}</h1>
        </div>
    );
}

useContext vs Redux : quand choisir quoi

Le choix entre useContext et Redux dépend de l'échelle et de la complexité de la gestion d'état. useContext + useReducer est un remplacement léger de Redux pour les applications petites et moyennes. Il ne nécessite pas l'installation d'une bibliothèque externe, est plus facile à apprendre et suffit pour la plupart des tâches. Redux se justifie lorsqu'une architecture stricte avec middleware, outils de développement et mises à jour immuables est requise.

Le principal avantage de Redux par rapport à useContext est l'optimisation des re-rendus. Par défaut, lorsque la valeur dans un Provider change, tous les consommateurs du contexte sont restitués. Redux avec useSelector et shallowEqual permet aux composants de s'abonner uniquement à des parties spécifiques de l'état, ce qui réduit considérablement le nombre de re-rendus dans les grandes applications. Le contexte peut également être optimisé en le divisant en nombreux petits contextes.

CritèreuseContextRedux
ComplexitéAucune dépendance externeNécessite la configuration du store et du middleware
Re-rendusTous les consommateurs à tout changementUniquement ceux abonnés à une slice spécifique
DevToolsReact DevToolsRedux DevTools avec voyage dans le temps
MiddlewareNon supportéRedux Thunk, Saga, Observable
Quand choisirApplications moyennes, 3–5 contextesGrandes applications avec logique métier complexe

Selon les Mainteneurs de Redux — Quand utiliser Redux (2024), 70 % des applications React n'ont pas besoin de Redux. Si vous avez moins de 50 composants et que l'état n'implique pas de logique complexe avec mise en cache, debounce et effets secondaires — useContext + useReducer est plus que suffisant. Redux ajoute du code standard et doit être utilisé consciemment.

Erreurs typiques avec useContext

L'erreur la plus courante est la recréation de l'objet value à chaque rendu du Provider. Si vous passez value={{ user, login }} au Provider, un nouvel objet est créé à chaque rendu du Provider, ce qui provoque le re-rendu de tous les consommateurs même si les données n'ont pas changé. La solution est de mémoïser la valeur avec useMemo ou d'utiliser des contextes séparés pour les données qui changent fréquemment et rarement.

  • Re-rendus inutiles — un nouvel objet value à chaque rendu du Provider. Utilisez useMemo pour mémoïser la valeur.
  • Contexte trop volumineux — un seul Provider avec des dizaines de champs force tous les composants enfants à se restituer lorsqu'un champ change. Divisez en plusieurs contextes par signification.
  • Absence de defaultValue — si aucun Provider n'est trouvé, useContext retourne defaultValue, et s'il est undefined, chaque appel lèvera une TypeError.
  • Providers imbriqués du même type — la redéfinition du contexte à des niveaux profonds peut être source de confusion et conduire à des valeurs inattendues.
jsx
// ❌ Nouvel objet à chaque rendu — tous les consommateurs se re-rendent
<AuthContext.Provider value={{ user, login }}>{children}</AuthContext.Provider>

// ✅ Valeur mémoïsée — re-rendu uniquement lorsque user ou login change
const authValue = useMemo(() => ({ user, login }), [user, login]);
<AuthContext.Provider value={authValue}>{children}</AuthContext.Provider>

Pour résoudre le problème du « grand contexte », divisez l'état global en groupes logiques : AuthContext, ThemeContext, I18nContext. Chaque contexte est responsable de son propre domaine et se met à jour indépendamment. C'est plus simple que d'essayer d'optimiser un contexte géant via useMemo et offre un comportement de re-rendu plus prévisible.

Foire aux questions

Peut-on modifier le contexte à partir d'un composant enfant ?

Oui, si vous passez une fonction mutatrice dans le value du Provider. Le modèle typique consiste à stocker l'état dans le Provider et à transmettre à la fois les données et les fonctions de mise à jour via useContext. Les composants enfants appellent ces fonctions, et le changement d'état dans le Provider met automatiquement à jour tous les consommateurs. C'est un remplacement de base de Redux pour les petites applications.

Qu'est-ce qui est le plus rapide — useContext ou Redux ?

Pour les scénarios simples, useContext est plus rapide en raison de l'absence de surcharge du store et du middleware. Mais avec des mises à jour fréquentes et de nombreux consommateurs, Redux l'emporte car ses sélecteurs (useSelector) s'abonnent à des parties spécifiques de l'état, tandis que useContext restitue tous les consommateurs à tout changement. Pour les applications à haute fréquence de mises à jour (animations, temps réel), choisissez Redux ou des bibliothèques spécialisées.

Peut-on utiliser useContext en dehors d'un composant React ?

Non. useContext, comme tous les hooks, ne peut être appelé qu'à l'intérieur d'un composant fonctionnel React ou d'un hook personnalisé. Si vous avez besoin d'obtenir la valeur du contexte dans une fonction ordinaire (par exemple, dans un utilitaire ou un service), passez-la en paramètre depuis le composant ou utilisez un module séparé avec un état global en dehors de React.

Comment fonctionne useContext avec TypeScript ?

Le typage du contexte dans TypeScript se fait en spécifiant le type dans createContext : createContext<AuthContextType | null>(null). Cela garantit que useContext(AuthContext) retourne une valeur du type correct. Un modèle pratique consiste à créer un hook personnalisé useAuth qui appelle useContext, vérifie s'il est null et lance une erreur claire : « useAuth doit être utilisé à l'intérieur d'AuthProvider ».

Pourquoi useContext retourne-t-il undefined alors qu'un Provider existe ?

La raison la plus courante est que le composant consommateur n'est pas à l'intérieur du Provider correspondant. Vérifiez que le Provider englobe toute la sous-arborescence où useContext est utilisé. La deuxième raison — un objet de contexte différent a été passé au Provider : le développeur crée un contexte avec createContext mais utilise useContext avec une instance différente de createContext.

Résumé

  • useContext — hook pour lire une valeur du contexte React, éliminant le besoin de props drilling.
  • createContext — crée un objet de contexte avec un Provider pour transmettre les données et un defaultValue pour les cas sans Provider.
  • Mémoïser la valeur — utilisez useMemo pour la valeur du Provider afin d'éviter les re-rendus inutiles des consommateurs.
  • Diviser les contextes — divisez l'état global en plusieurs petits contextes par groupes logiques.
  • Hiérarchie des Providers — les Providers du même type peuvent être imbriqués pour redéfinir les valeurs dans une partie de l'arborescence.
  • useContext + useReducer — un remplacement léger de Redux pour les applications moyennes sans dépendances externes.
  • Ne remplace pas Redux — pour une logique complexe avec middleware et mises à jour fréquentes, choisissez Redux avec des sélecteurs.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi