useContext
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éé aveccreateContext
. 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 HookuseContext()
. - 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 avecObject.is
. Sauter des rendus avecmemo
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 leSomeContext
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)
.
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"
.
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.
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 :
- Vous faites le rendu de
<SomeContext.Provider>
dans le mĂȘme composant (ou en dessous) que celui oĂč vous appelezuseContext()
. Déplacez<SomeContext.Provider>
au-dessus et en-dehors du composant appelantuseContext()
. - 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. - 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 leSomeContext
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 commewindow.SomeContext1
etwindow.SomeContext2
et en vérifiant le résultat dewindow.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.