React Context existe depuis un certain temps. Avec l'avénement de React hooks, c'est maintenant beaucoup mieux. Il présente de nombreux avantages, notamment le fait que l'API de contexte ne nécessite aucune bibliothèque tierce. Nous pouvons l'utiliser dans les applications React pour gérer notre état comme redux.
Dans cet article, nous allons gérer notre état avec React Context, pour voir par nous-mêmes s'il vaut mieux que redux concernant la gestion de l'état. Au passage, ce poste est le suivi de mon précédent 7 étapes pour comprendre React Redux.
Note: Cet article ne couvre que l'API de contexte. Nous allons construire le même projet avec React Context. Si vous êtes intéressé par la façon dont on gére l'état avec redux, mon article précédent pourrait vous aider ici.
Sinon, commençons
Sorry for the interrupt!
If you're interested in learning React in a comprehensive way, I highly recommend this bestseller course: React - The Complete Guide (incl Hooks, React Router, Redux)
It's an affiliate link, so by purchasing, you support the blog at the same time.- Conditions préalables
- Configuration du projet
- Créer un contexte
- Fournir le contexte
- Consommer le contexte
- Améliorez le contexte avec useReducer
- Redux VS the React Context: qui a gagné?
Conditions préalables
Pour pouvoir suivre, vous devez connaître au moins les bases des fonctionnalités de React et en particulier React Hooks. Une bonne compréhension de redux peut également aider.
Configuration du projet
Si vous êtes prêt à y aller, nous pouvons maintenant créer une nouvelle application React en exécutant:
npx create-react-app react-context-hooks-example
Ensuite, nous allons créer quelques fichiers.
- Ajoutez un dossier
containers
dans lesrc
, puis créez le fichierArticles.js
.
import React, { useState } from "react"
import Article from "../components/Article/Article"
const Articles = () => {
const [articles, setArticles] = useState([
{ id: 1, title: "post 1", body: "Quisque cursus, metus vitae pharetra" },
{ id: 2, title: "post 2", body: "Quisque cursus, metus vitae pharetra" },
])
return (
<div>
{articles.map(article => (
<Article key={article.id} article={article} />
))}
</div>
)
}
export default Articles
- Ajoutez un dossier
components
dans lesrc
, puis créezAddArticle / AddArticle.js
etArticle / Article.js
. - Dans
Article.js
import React from "react"
import "./Article.css"
const article = ({ article }) => (
<div className="article">
<h1>{article.title}</h1>
<p>{article.body}</p>
</div>
)
export default article
- In the
AddArticle.js
import React, { useState } from "react"
import "./AddArticle.css"
const AddArticle = () => {
const [article, setArticle] = useState()
const handleArticleData = e => {
setArticle({
...article,
[e.target.id]: e.target.value,
})
}
const addNewArticle = e => {
e.preventDefault()
// The logic will come later
}
return (
<form onSubmit={addNewArticle} className="add-article">
<input
type="text"
id="title"
placeholder="Title"
onChange={handleArticleData}
/>
<input
type="text"
id="body"
placeholder="Body"
onChange={handleArticleData}
/>
<button>Add article</button>
</form>
)
}
export default AddArticle
- Dans
App.js
import React, { Fragment } from "react"
import Articles from "./containers/Articles"
import AddArticle from "./components/AddArticle/AddArticle"
function App() {
return (
<Fragment>
<AddArticle />
<Articles />
</Fragment>
)
}
export default App
Bon si vous avez terminé avec toutes les instructions ci-dessus, nous pouvons continuer et commencer à implémenter l'API contextuelle.
Créer un contexte
Un contexte nous aide à gérer l'état sans transmettre les props sur chaque composant. Seul le composant nécessaire consommera le contexte. Pour l'implémenter, nous devons créer (c'est facultatif) un nouveau dossier nommé context
dans notre projet, et ajouter ce code ci-dessous àaricleContext.js
.
- Dans
context/aricleContext.js
import React, { createContext, useState } from "react"
export const ArticleContext = createContext()
const ArticleProvider = ({ children }) => {
const [articles, setArticles] = useState([
{ id: 1, title: "post 1", body: "Quisque cursus, metus vitae pharetra" },
{ id: 2, title: "post 2", body: "Quisque cursus, metus vitae pharetra" },
])
const saveArticle = article => {
const newArticle = {
id: Math.random(), // not really unique but it's just an example
title: article.title,
body: article.body,
}
setArticles([...articles, newArticle])
}
return (
<ArticleContext.Provider value={{ articles, saveArticle }}> {children} </ArticleContext.Provider> )
}
export default ArticleProvider
La bibliothèque React nous donne accès à une méthode appelée createContext
. Nous pouvons l'utiliser pour créer un contexte comme vous pouvez le deviner. Ici, nous ne transmettons rien à notre contexte ArticleContext
, mais vous pouvez passer comme argument, un objet, tableau, chaîne de caractères, etc. Ensuite, nous définissons une fonction qui nous aidera à distribuer les données via le Provider
. Nous donnons à notre Provider
deux valeurs: la liste des articles et la méthode pour ajouter un article. Par ailleurs, articles: articles
etsaveArticle: saveArticle
sont les mêmes que articles
et saveArticle
c'est juste une syntaxe pratique au cas où cela vous dérouterait.
Maintenant que nous avons un contexte, cependant, nous devons fournir le contexte afin de le consommer. Pour ce faire, nous devons envelopper notre composant supérieur avec ArticleProvider
et App.js
pourrait être le parfait composant. Alors, ajoutons-le à App.js
.
Fournir le contexte
- Dans
App.js
import React from "react"
import ArticleProvider from "./context/articleContext"
import Articles from "./containers/Articles"
import AddArticle from "./components/AddArticle/AddArticle"
function App() {
return (
<ArticleProvider> <AddArticle /> <Articles /> </ArticleProvider> )
}
export default App
Comme vous le voyez ici, nous importons d'abord notre fournisseur de contexte ArticleProvider
et les composants d'enveloppe qui doivent consommer le contexte. Et qu'en est-il de la consommation du contexte? et comment nous pouvons le faire. Vous pourriez être surpris de voir à quel point il est facile de consommer le contexte avec React hooks. Alors, faisons ça.
Consommer le contexte
Nous allons consommer le contexte avec deux composants: Articles.js
etAddArticle.js
.
- Dans
Articles.js
import React, { useContext } from "react"
import { ArticleContext } from "../context/articleContext"
import Article from "../components/Article/Article"
const Articles = () => {
const { articles } = useContext(ArticleContext) return (
<div>
{articles.map(article => (
<Article key={article.id} article={article} />
))}
</div>
)
}
export default Articles
Avec React hooks, nous avons maintenant accès au hook useContext
. Et comme vous pouvez le deviner, cela nous aidera à consommer le contexte. En passant notre contexte ArticleContext
comme argument à useContext
, il nous donne accès à notre état contenu dans articleContext.js
. Ici, nous avons juste besoin de articles
. Par conséquent, nous le retirons et itérons nos articles avant de les afficher. Passons maintenant à AddArticle.js
- Dans
AddArticle.js
import React, { useState, useContext } from "react"import "./AddArticle.css"
import { ArticleContext } from "../../context/articleContext"
const AddArticle = () => {
const { saveArticle } = useContext(ArticleContext) const [article, setArticle] = useState()
const handleArticleData = e => {
setArticle({
...article,
[e.target.id]: e.target.value,
})
}
const addNewArticle = e => {
e.preventDefault()
saveArticle(article)
}
return (
<form onSubmit={addNewArticle} className="add-article">
<input
type="text"
id="title"
placeholder="Title"
onChange={handleArticleData}
/>
<input
type="text"
id="body"
placeholder="Body"
onChange={handleArticleData}
/>
<button>Add article</button>
</form>
)
}
export default AddArticle
Comme dans le cas précédent, ici encore, nous utilisons useContext
pour extraire saveArticle
de notre contexte. Avec cela, nous pouvons maintenant ajouter en toute sécurité un nouvel article via le contexte React.
Nous gérons maintenant l'état de l'ensemble de notre application via le contexte React. Cependant, nous pouvons toujours l'améliorer via un autre hook nommé useReducer
.
Améliorez le contexte avec useReducer
Le hook useReducer
est une alternative à useState
. Il est principalement utilisé pour des états plus complexes. useReducer
accepte une fonction de réduction avec l'état initial de notre application React, et retourne l'état actuel, puis distribue une fonction.
Ce sera beaucoup plus clair lorsque nous commencerons à le mettre en œuvre. Maintenant, nous devons créer un nouveau fichier reducer.js
dans notre dossier contextuel et ajouter ce bloc de code ci-dessous.
- Dans
reducer.js
export const reducer = (state, action) => {
switch (action.type) {
case "ADD_ARTICLE":
return [
...state,
{
id: Math.random(), // not really unique but it's just an example
title: action.article.title,
body: action.article.body,
},
]
default:
return state
}
}
Comme vous pouvez le voir, la fonction reducer
reçoit deux paramètres: state
et action
. Ensuite, nous vérifions si le type d'action est égal à ADD_ARTICLE
(vous pouvez créer une constante ou un fichier pour éviter les fautes de frappe), si c'est le cas, ajoutez un nouvel article à notre état. Cette syntaxe peut être familière si vous avez utilisé redux. Maintenant, la logique pour ajouter un nouvel article est gérée par le réducteur. Nous n'avons pas encore terminé, ajoutons-le à notre fichier de contexte.
import React, { createContext, useReducer } from "react"import { reducer } from "./reducer"export const ArticleContext = createContext()
const ArticleProvider = ({ children }) => {
const [articles, dispatch] = useReducer(reducer, [ { id: 1, title: "post 1", body: "Quisque cursus, metus vitae pharetra" }, { id: 2, title: "post 2", body: "Quisque cursus, metus vitae pharetra" }, ])
return (
<ArticleContext.Provider value={{ articles, dispatch }}>
{children}
</ArticleContext.Provider>
)
}
export default ArticleProvider
Ici, nous commençons par importer le hook useReducer
et notre fonction reducer
. Comme je l'ai mentionné plus tôt, useReducer
prend une fonction. Par conséquent, nous devons lui passer notre fonction de reducer
et comme deuxième argument l'état initial de notre application. Maintenant, useReducer
nous donne accès à nos articles
et à une fonction dispatch
(vous pouvez le nommer comme bon vous semble). Et nous pouvons maintenant mettre à jour notre fournisseur avec ces nouvelles valeurs données par useReducer
.
Vous pouvez déjà voir que notre fichier de contexte est maintenant beaucoup plus propre. En renommant la fonction qui ajoute un nouvel article à dispatch
, nous devons maintenant mettre à jour un peu notre fichier AddArticle.js
.
- Dans
AddArticle.js
import React, { useState, useContext } from "react"
import "./AddArticle.css"
import { ArticleContext } from "../../context/articleContext"
const AddArticle = () => {
const { dispatch } = useContext(ArticleContext) const [article, setArticle] = useState()
const handleArticleData = e => {
setArticle({
...article,
[e.target.id]: e.target.value,
})
}
const addNewArticle = e => {
e.preventDefault()
dispatch({ type: "ADD_ARTICLE", article })
}
return (
<form onSubmit={addNewArticle} className="add-article">
<input
type="text"
id="title"
placeholder="Title"
onChange={handleArticleData}
/>
<input
type="text"
id="body"
placeholder="Body"
onChange={handleArticleData}
/>
<button>Add article</button>
</form>
)
}
export default AddArticle
Maintenant, au lieu de retirer saveArticle
, nous obtenons maintenant la fonction dispatch
. Il attend un type d'action ADD_ARTICLE
et une valeur article
qui sera le nouvel article. Avec cela, notre projet est désormais géré via l'API contextuelle et React Hooks.
Redux VS the React Context: qui a gagné?
Vous pouvez maintenant voir clairement la différence entre Redux et React Context à travers leurs implémentations sur notre projet. Cependant, Redux est loin d'être mort ou d'être tué par React Context. Redux est certes lourd à implementer et nécessite un tas de bibliothèques. Mais cela reste une excellente solution pour le gérer nos etats.
L'Api contextuelle avec hooks est beaucoup plus facile à implémenter et n'augmentera pas la taille de votre bundle.
Mais qui gagne? à mon avis, pour une mise à jour à basse fréquence comme les paramètres régionaux, les changements de thème, l'authentification des utilisateurs, etc., React context est parfaitement bien. Mais avec un état plus complexe qui a des mises à jour à haute fréquence, le contexte React ne sera pas une bonne solution. Parce que le contexte React déclenche un nouveau rendu à chaque mise à jour, et l'optimiser manuellement peut être très difficile. Et là, une solution comme Redux est beaucoup plus utile et facile à implémenter afin de gérer notre état.
Vous trouverez le projet final ici