Mettre à jour un contexte React depuis son consumer
Parmi les dernières nouveautés de ReactJS qui ont grandement amélioré le DX (Developer eXperience) du framework, il y a le Context API et les hooks. Dans cet article, nous nous intéresserons au Context API.
Je ne vais pas expliquer dans le détail comment fonctionne le Context API dans cet article. Si vous ne savez pas de quoi il s’agit, je vous invite à lire rapidement l'article sur les différentes manières de passer des données à un composant React.
Merci à @alexislepresle pour son idée d’article ! Vous pouvez, vous aussi, contribuer au blog en demandant un sujet en particulier sur le serveur discord (lien en pied de page).
Comment modifier les valeurs d’un contexte depuis un de ses enfants ?
Pour rappel, le Context API permet de stocker des données et de les rendre accessibles à n’importe quel enfant qui souhaite l’utiliser. Cela est valide quel que soit le niveau de l’enfant dans la hiérarchie des composants.
const MyContext = React.createContext()
const MyComponent = () => {
const count = useContext(MyContext)
return (
<div>price: {count}</div>
)
}
const App = () => (
<MyContext.Provider value={2}>
<div>
<MyComponent />
<MyComponent />
</div>
</MyContext.Provider>
)
Si on simplifie au maximum, les contextes sont faits pour transmettre de l’information du haut vers le bas de l’arbre des composants. Comment pourrait-on faire aller de l’information dans le sens inverse ? Ou juste modifier le contexte sans même remonter de l’information ?
En utilisant les fonctions, les closures. Comme ce sont de simples valeurs comme les autres, vous pouvez stocker des fonctions dans votre contexte. Si vous stockez une fonction qui est capable de modifier le contenu du contexte, tous les enfants de celui-ci pourront l’utiliser et donc le modifier.
Pour rendre les valeurs du contexte facilement modifiables, je vais utiliser le passage par référence de JavaScript (inspiré du C, bien-sûr).
const MyContext = React.createContext()
const MyComponent = () => {
const { count } = useContext(MyContext)
return (
<div>price: {count}</div>
)
}
const App = () => {
const [count] = useState(0)
return (
<MyContext.Provider value={{ count }}>
<div>
<MyComponent />
<MyComponent />
</div>
</MyContext.Provider>
)
}
Avec le code précédent, nous obtenons le même résultat. Nous avons simplement déplacé le stockage des données vers le state du composant parent.
Il nous suffit maintenant d’ajouter une fonction qui modifie ce state pour pouvoir appliquer la modification depuis un enfant.
const MyContext = React.createContext()
const MyComponent = () => {
const { count, increment } = useContext(MyContext)
return (
<div onClick={increment}>price: {count}</div>
)
}
const App = () => {
const [count, updateCount] = useState(0)
function increment() {
updateCount(count + 1)
}
return (
<MyContext.Provider value={{ count, increment }}>
<div>
<MyComponent />
<MyComponent />
</div>
</MyContext.Provider>
)
}
Maintenant lorsque l’utilisateur clique sur le prix, celui-ci augment de 1 à chaque fois.
Pour résumé, dans le composant où nous voulons utiliser le contexte, nous stockons les données dans le state de ce composant et nous créons une fonction capable de modifier ce state. Ensuite, nous pouvons passer le state et la fonction comme valeur du contexte.
Il devient alors possible depuis l’enfant de récupérer la fonction de modification et de l’utiliser pour mettre à jour le contexte.
Pour aller plus loin :