useContext est un Hook React qui vous permet de lire et de vous abonner Ă  un contexte depuis votre composant.

const value = useContext(SomeContext)

Référence

useContext(SomeContext)

Appelez useContext Ă  la racine de votre composant pour lire et vous abonner au contexte.

import { useContext } from 'react';

function MyComponent() {
const theme = useContext(ThemeContext);
// ...

Voir d’autres exemples plus bas.

ParamĂštres

  • SomeContext : le contexte que vous avez prĂ©alablement créé avec createContext. Le contexte lui-mĂȘme ne contient pas d’information, il reprĂ©sente seulement le type d’information que vous pouvez fournir ou lire depuis des composants.

Valeur renvoyée

useContext renvoie la valeur du contexte pour le composant qui l’appelle. C’est dĂ©terminĂ© par la value passĂ©e par le SomeContext.Provider le plus proche au-dessus du composant appelant. S’il n’y a pas un tel fournisseur, alors la valeur renvoyĂ©e sera la defaultValue que vous avez passĂ©e Ă  createContext pour ce contexte. La valeur renvoyĂ©e est toujours Ă  jour. React refait automatiquement le rendu des composants qui lisent un contexte lorsque ce dernier change.

Limitations

  • L’appel Ă  useContext() dans un composant n’est pas affectĂ© par les fournisseurs renvoyĂ©s par le mĂȘme composant. Le <Context.Provider> correspondant doit figurer au-dessus du composant qui appelle le Hook useContext().
  • React fait automatiquement le rendu de tous les enfants qui utilisent un contexte spĂ©cifique, en commençant par le fournisseur qui reçoit une value diffĂ©rente. La valeur prĂ©cĂ©dente et la suivante sont comparĂ©es avec Object.is. Sauter des rendus avec memo n’empĂȘche pas les enfants de recevoir une nouvelle valeur de contexte.
  • Le contexte peut ĂȘtre cassĂ© si votre systĂšme de construction produit des modules dupliquĂ©s en sortie (ce qui peut arriver avec les liens symboliques). Passer quelque chose via le contexte ne marche que si le SomeContext que vous avez utilisĂ© pour fournir le contexte et le SomeContext que vous utilisez pour le lire sont exactement le mĂȘme objet, ce qui est dĂ©terminĂ© par une comparaison ===.

Utilisation

Transmettre des donnĂ©es en profondeur dans l’arbre

Appelez useContext au niveau le plus élevé de votre composant pour lire et vous abonner au contexte.

import { useContext } from 'react';

function Button() {
const theme = useContext(ThemeContext);
// ...

useContext renvoie la valeur du contexte pour le contexte que vous avez passĂ©. Pour dĂ©finir la valeur du contexte, React remonte dans l’arbre des composants Ă  la recherche du fournisseur de contexte le plus proche pour ce contexte particulier.

Pour passer un contexte Ă  un Button, il faut enrober ce composant ou l’un de ses parents dans le fournisseur de contexte correspondant :

function MyPage() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
);
}

function Form() {
// ... faire le rendu des boutons à l'intérieur ...
}

Le nombre de couches de composants qu’il y a entre le fournisseur et le Bouton importe peu. Un Button situĂ© n’importe oĂč Ă  l’intĂ©rieur du Form reçoit la valeur "dark" quand il appelle useContext(ThemeContext).

PiĂšge

useContext() cherche toujours le fournisseur le plus proche au-dessus du composant qui l’appelle. Il cherche vers le haut et ne prend pas en compte les fournisseurs situĂ©s dans le composant Ă  partir duquel vous appelez useContext().

import { createContext, useContext } from 'react';

const ThemeContext = createContext(null);

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  )
}

function Form() {
  return (
    <Panel title="Bienvenue">
      <Button>S'inscrire</Button>
      <Button>Se connecter</Button>
    </Panel>
  );
}

function Panel({ title, children }) {
  const theme = useContext(ThemeContext);
  const className = 'panel-' + theme;
  return (
    <section className={className}>
      <h1>{title}</h1>
      {children}
    </section>
  )
}

function Button({ children }) {
  const theme = useContext(ThemeContext);
  const className = 'button-' + theme;
  return (
    <button className={className}>
      {children}
    </button>
  );
}


Mettre à jour les données passées au contexte

Vous voudrez souvent que le contexte change avec le temps. Pour mettre Ă  jour le contexte, associez-le Ă  un Ă©tat. DĂ©clarez une variable d’état dans le composant parent, et passez l’état actuel au fournisseur en tant que valeur de contexte.

function MyPage() {
const [theme, setTheme] = useState('dark');
return (
<ThemeContext.Provider value={theme}>
<Form />
<Button onClick={() => {
setTheme('light');
}}>
Passer au thĂšme clair
</Button>
</ThemeContext.Provider>
);
}

DĂ©sormais, tout Button Ă  l’intĂ©rieur du fournisseur recevra la valeur actuelle de theme. Si vous appelez setTheme pour mettre Ă  jour la valeur de theme que vous avez passĂ©e au fournisseur, tous les Button referont leurs rendus avec la nouvelle valeur "light".

Exemples de mises Ă  jour du contexte

Exemple 1 sur 5 Â·
Mettre Ă  jour une valeur via le contexte

Dans cet exemple, le composant MyApp contient une variable d’état qui est ensuite passĂ©e au fournisseur ThemeContext. Cocher la case « Utiliser le mode sombre Â» met Ă  jour cet Ă©tat. Changer la valeur fournie refait le rendu de tous les composants utilisant ce contexte.

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

const ThemeContext = createContext(null);

export default function MyApp() {
  const [theme, setTheme] = useState('light');
  return (
    <ThemeContext.Provider value={theme}>
      <Form />
      <label>
        <input
          type="checkbox"
          checked={theme === 'dark'}
          onChange={(e) => {
            setTheme(e.target.checked ? 'dark' : 'light')
          }}
        />
        Utiliser le mode sombre
      </label>
    </ThemeContext.Provider>
  )
}

function Form({ children }) {
  return (
    <Panel title="Bienvenue">
      <Button>S'inscrire</Button>
      <Button>Se connecter</Button>
    </Panel>
  );
}

function Panel({ title, children }) {
  const theme = useContext(ThemeContext);
  const className = 'panel-' + theme;
  return (
    <section className={className}>
      <h1>{title}</h1>
      {children}
    </section>
  )
}

function Button({ children }) {
  const theme = useContext(ThemeContext);
  const className = 'button-' + theme;
  return (
    <button className={className}>
      {children}
    </button>
  );
}

Remarquez que value="dark" passe la chaßne de caractÚres "dark", mais que value={theme} passe la valeur de la variable JavaScript theme en utilisant les accolades de JSX. Ces accolades vous permettent également de passer des valeurs de contexte qui ne sont pas des chaßnes de caractÚres.


Spécifier une valeur de secours par défaut

Si React ne trouve aucun fournisseur pour ce contexte particulier dans l’arbre du parent, la valeur de contexte renvoyĂ©e par useContext() sera Ă©gale Ă  la valeur par dĂ©faut que vous avez spĂ©cifiĂ©e lorsque vous avez créé ce contexte :

const ThemeContext = createContext(null);

La valeur par défaut ne change jamais. Si vous voulez mettre à jour le contexte, associez-le avec un état comme décrit plus haut.

Vous pouvez souvent utiliser une valeur par dĂ©faut plus significative que null, comme par exemple :

const ThemeContext = createContext('light');

De cette façon, si par inadvertance vous faites le rendu de certains composants sans le bon contexte associĂ©, ça ne cassera pas. Ça permet aussi Ă  votre composant de se comporter correctement dans un environnement de test sans avoir Ă  dĂ©finir tout un tas de fournisseurs pour les tests.

Dans l’exemple ci-dessous, le bouton « Changer de thĂšme Â» est toujours en clair, parce qu’il se situe en dehors de tout contexte fournissant le thĂšme, et la valeur par dĂ©faut de ce thĂšme est 'light'. Essayez de changer la valeur par dĂ©faut Ă  'dark'.

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

const ThemeContext = createContext('light');

export default function MyApp() {
  const [theme, setTheme] = useState('light');
  return (
    <>
      <ThemeContext.Provider value={theme}>
        <Form />
      </ThemeContext.Provider>
      <Button onClick={() => {
        setTheme(theme === 'dark' ? 'light' : 'dark');
      }}>
        Changer de thĂšme
      </Button>
    </>
  )
}

function Form({ children }) {
  return (
    <Panel title="Bienvenue">
      <Button>S'inscrire</Button>
      <Button>Se connecter</Button>
    </Panel>
  );
}

function Panel({ title, children }) {
  const theme = useContext(ThemeContext);
  const className = 'panel-' + theme;
  return (
    <section className={className}>
      <h1>{title}</h1>
      {children}
    </section>
  )
}

function Button({ children, onClick }) {
  const theme = useContext(ThemeContext);
  const className = 'button-' + theme;
  return (
    <button className={className} onClick={onClick}>
      {children}
    </button>
  );
}


Surcharger le contexte pour une partie de l’arbre

Vous pouvez surcharger le contexte pour une partie de l’arbre en l’enrobant avec un fournisseur ayant une valeur diffĂ©rente.

<ThemeContext.Provider value="dark">
...
<ThemeContext.Provider value="light">
<Footer />
</ThemeContext.Provider>
...
</ThemeContext.Provider>

Vous pouvez imbriquer et surcharger les fournisseurs autant de fois que nécessaire.

Exemples de surcharge de contexte

Exemple 1 sur 2 Â·
Surcharger un thĂšme

Ici, le bouton Ă  l’intĂ©rieur du Footer reçoit une valeur de contexte diffĂ©rente ("light") de celle reçue par les boutons Ă  l’extĂ©rieur ("dark").

import { createContext, useContext } from 'react';

const ThemeContext = createContext(null);

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  )
}

function Form() {
  return (
    <Panel title="Bienvenue">
      <Button>S'inscrire</Button>
      <Button>Se connecter</Button>
      <ThemeContext.Provider value="light">
        <Footer />
      </ThemeContext.Provider>
    </Panel>
  );
}

function Footer() {
  return (
    <footer>
      <Button>ParamĂštres</Button>
    </footer>
  );
}

function Panel({ title, children }) {
  const theme = useContext(ThemeContext);
  const className = 'panel-' + theme;
  return (
    <section className={className}>
      {title && <h1>{title}</h1>}
      {children}
    </section>
  )
}

function Button({ children }) {
  const theme = useContext(ThemeContext);
  const className = 'button-' + theme;
  return (
    <button className={className}>
      {children}
    </button>
  );
}


Optimiser les rendus lorsqu’on passe des objets et des fonctions

Vous pouvez passer n’importe quelle valeur via le contexte, y compris des objets et des fonctions.

function MyApp() {
const [currentUser, setCurrentUser] = useState(null);

function login(response) {
storeCredentials(response.credentials);
setCurrentUser(response.user);
}

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

Ici, la valeur de contexte est un objet JavaScript avec deux propriĂ©tĂ©s, dont l’une est une fonction. À chaque fois que MyApp fait son rendu (par exemple lors d’un changement de route), ce sera un objet diffĂ©rent pointant vers une fonction diffĂ©rente, React devra donc refaire le rendu de tous les composants situĂ©s en profondeur dans l’arbre qui appellent useContext(AuthContext).

Ce n’est pas un problĂšme pour les petites applis. Cependant, il est inutile de faire le rendu si les donnĂ©es sous-jacentes, comme currentUser, n’ont pas changĂ©. Pour aider React Ă  tirer parti de ça, vous pouvez enrober la fonction login dans un Hook useCallback et la crĂ©ation de l’objet dans un Hook useMemo. C’est une optimisation de performances :

import { useCallback, useMemo } from 'react';

function MyApp() {
const [currentUser, setCurrentUser] = useState(null);

const login = useCallback((response) => {
storeCredentials(response.credentials);
setCurrentUser(response.user);
}, []);

const contextValue = useMemo(() => ({
currentUser,
login
}), [currentUser, login]);

return (
<AuthContext.Provider value={contextValue}>
<Page />
</AuthContext.Provider>
);
}

GrĂące Ă  ce changement, mĂȘme si MyApp a besoin d’un nouveau rendu, les composants appelant useContext(AuthContext) pourront se l’épargner, Ă  moins que currentUser ait changĂ©.

Apprenez-en davantage sur useMemo et useCallback.


Dépannage

Mon composant ne voit pas la valeur de mon fournisseur

Il y a plusieurs raisons pour ça se produise :

  1. Vous faites le rendu de <SomeContext.Provider> dans le mĂȘme composant (ou en dessous) que celui oĂč vous appelez useContext(). DĂ©placez <SomeContext.Provider> au-dessus et en-dehors du composant appelant useContext().
  2. Vous avez peut-ĂȘtre oubliĂ© d’enrober votre composant avec <SomeContext.Provider> ou vous l’avez placĂ© dans une partie diffĂ©rente de votre arbre que celle que vous imaginiez. VĂ©rifiez si la hiĂ©rarchie est correcte en utilisant les outils de dĂ©veloppement React.
  3. Il se peut que vous rencontriez un problĂšme de build avec vos outils qui fait que le SomeContext vu par le composant fournisseur et le SomeContext vu par le composant qui le lit sont deux objets diffĂ©rents. Ça peut arriver si vous utilisez des liens symboliques par exemple. Vous pouvez vous en assurer en les affectant Ă  des variables globales comme window.SomeContext1 et window.SomeContext2 et en vĂ©rifiant le rĂ©sultat de window.SomeContext1 === window.SomeContext2 dans la console. Si elles sont diffĂ©rentes, corrigez le problĂšme au niveau de l’outil de build.

Je reçois undefined de mon contexte bien que la valeur par défaut soit différente

Vous avez peut-ĂȘtre un fournisseur sans value dans l’arbre :

// đŸš© Ça ne marche pas : pas de prop « value Â»
<ThemeContext.Provider>
<Button />
</ThemeContext.Provider>

Oublier de spécifier la value revient à passer value={undefined}.

Il se peut Ă©galement que vous ayez utilisĂ© par erreur un autre nom de prop :

// đŸš© Ça ne marche pas : la prop doit s'appeler « value Â»
<ThemeContext.Provider theme={theme}>
<Button />
</ThemeContext.Provider>

Dans ces deux cas, vous devriez voir un message d’alerte de React dans la console. Pour les corriger, appelez la prop value :

// ✅ Passer la prop « value Â»
<ThemeContext.Provider value={theme}>
<Button />
</ThemeContext.Provider>

Notez que la valeur par dĂ©faut de votre appel Ă  createContext(defaultValue) est seulement utilisĂ©e s’il n’y a pas d’autre fournisseur correspondant au-dessus. S’il y a un composant <SomeContext.Provider value={undefined}> quelque part dans l’arbre parent, le composant qui appelle useContext(SomeContext) recevra undefined pour la valeur de contexte.