Redux VS React Context: Lequel devriez-vous choisir?

Jan 02, 2020☕ ☕ 10 min Follow me on Twitter

Subscribe to receive the free weekly article

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

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 fichier Articles.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éez AddArticle / 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

#react#redux#hooks

Support my work

Get articles in your inbox