Comprendre React Context en faisant un Dark mode

ahmedbouras

Ahmed Bouras

Posted on April 1, 2023

Comprendre React Context en faisant un Dark mode

Dans ce tutoriel nous allons voir ensemble ce qu'est React Context et finir cette explication par un petit dark mode pour la mise en pratique.

Déjà, c'est quoi React Context ?

React Context (ou l'API de Context pour les plus intimes) va nous permettre de rendre disponible des données et/ou des fonctions, dans toute notre application.

Sans React Context, il est possible de le faire en passant par les props d'un parent à son enfant. Cependant, imaginez que vous ayez une architecture où vous avez un parent, qui à un enfant, qui à lui même un enfant, qui à lui même un enfant, etc.
Il serait fastidieux de mettre cela en place.

prop drilling image
On appelle ça le prop drilling.

Context existe donc pour éviter le prop drilling.
Pour faire une métaphore, imaginez une famille dans une maison où l'on a le père, le fils, le petit-fils et l'arrière petit-fils.

Avec le prop drilling :
Le père souhaite donner les clés de la voiture familial à son arrière petit-fils. Pour cela, il doit donner les clés à son fils, qui va devoir les donner à son petit-fils, qui les donnera enfin à son arrière petit-fils.

Avec Context :
Le père pose les clés de la voiture dans le salon et celui qui à besoin des clés n'aura qu'a les récupérer. Les clés sont disponible pour tout le monde, sans passer par un intermédiaire.
Mais n'oublions pas les bonnes manières… Il faudra les demander, avant de les prendre 😉

prop drilling vs context api

Maintenant que nous avons vu la théorie, faisons un peu de pratique avec notre dark mode.
gif jour nuit les visiteurs
Il y aura 3 étapes principales :

  • Créer le context
  • Englober notre app dans le context créé
  • Récupérer les données/fonctions de notre context

Juste pour le côté pratique, je vais tout mettre dans le dossier src, et configurer le css dans un seul endroit. Ne gardez que les fichiers suivants : index.js | index.css | App.js



/* index.css */

*, ::before, ::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
.app {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  width: 100vw;
  height: 100vh;
}
.dark-theme {
  background-color: #1B2430;
  color: #F1F1F1;
}
.content {
  width: 80%;
}


Enter fullscreen mode Exit fullscreen mode

Créons un peu de contenu pour nous permettre de voir le changement qui va s'opérer avec le dark mode ainsi que le bouton qui vas nous permettre de switcher avec ce mode.



// ToggleButton.js
export default function ToggleButton() {
  return <button>Toggle</button>
}


Enter fullscreen mode Exit fullscreen mode


// Content.js
import ToggleButton from "./ToggleButton";

export default function Content() {
  return (
    <div className="content">
      <h1>Hello world!</h1>
      <p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. 
         Voluptates id ratione voluptatibus iusto unde soluta 
         dicta cum nam, rerum sit labore at et ducimus nobis 
         expedita molestiae commodi nostrum eius voluptatem 
         reiciendis repellat accusamus placeat eveniet rem. 
         Consequuntur, ducimus dolorum. Sunt deserunt optio itaque 
         maxime eligendi temporibus magnam pariatur inventore.</p>
         <ToggleButton />
    </div>
  )
}


Enter fullscreen mode Exit fullscreen mode


// App.js
import Content from "./Content";

export default function App() {
  return (
    <div className="app">
      <Content />
    </div>
  )
}


Enter fullscreen mode Exit fullscreen mode

Maintenant que nous avons notre base, passons à ce qui nous intéresse vraiment et créons le fichier qui va fournir notre context : DarkModeProvider.js.

1. Créer le context

Pour créer un context, rien de plus simple, il suffit d'utiliser la commande suivante :
export const DarkModeContext = createContext();

🔴 Attention ! Cette commande doit se trouver en dehors de vos composants. Notre fichier ressemble maintenant à cela pour le moment :



// DarkModeProvider.js
import { createContext } from "react"

export const DarkModeContext = createContext();

// début du composant
export default function DarkModeProvider() {
  return (
    <div>

    </div>
  )
}
// fin du composant



Enter fullscreen mode Exit fullscreen mode

Pour la suite, nous allons créer une variable darkMode qui aura pour valeur true ou false afin de savoir si le dark mode est activé. À cela, nous allons ajouter une fonction qui nous permettra permettra de switcher entre ces deux valeurs.

Ça tombe bien, il y a un Hook que nous allons utiliser pour cette tâche et c'est useState.



import { createContext, useState } from "react"

export const DarkModeContext = createContext();

export default function DarkModeProvider() {
  const [darkMode, setDarkMode] = useState(false);

  function toggleDarkMode() {
    setDarkMode(!darkMode);
  }

  return (
    <div>

    </div>
  )
}


Enter fullscreen mode Exit fullscreen mode

On initialise darkMode à false car initialement notre site sera en clair (couleur par défaut) :
false -> clair
true -> sombre

Puis la fonction toggleDarkMode() permettra à chaque clique sur notre bouton, d'inverser les couleurs, c'est à dire de faire passer false à sa valeur inverse : true et ainsi de suite.

D'ailleurs, comment je fais pour transmettre cette fonction à mon bouton ToggleButton ?

2. Englober notre app dans le context créé

Il y a deux étapes pour "englober" notre app de notre context. On peut dire aussi que l'on fournis un context à notre app.

La première est d'englober notre composant App par le composant DarkModeProvider :



// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
import DarkModeProvider from "./DarkModeProvider";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <DarkModeProvider>
      <App />
    </DarkModeProvider>
  </React.StrictMode>
);


Enter fullscreen mode Exit fullscreen mode


// DarkModeProvider.js
import { createContext, useState } from "react"

export const DarkModeContext = createContext();

export default function DarkModeProvider({ children }) {
  const [darkMode, setDarkMode] = useState(false);

  function toggleDarkMode() {
    setDarkMode(!darkMode);
  }

  return (
    <DarkModeContext.Provider>
      {children}
    </DarkModeContext.Provider>
  )
}


Enter fullscreen mode Exit fullscreen mode

Ici, children correspond à notre composant App.

Autre petite étape avant de passer à la suite. On a rendu notre context disponible, c'est bien... Mais comment Context sait qu'il doit mettre telle ou telle donnée à disposition ?

Il faut les ajouter en tant que valeur comme ceci :



// DarkModeProvider.js
  return (
    <DarkModeContext.Provider 
    value={ {darkMode, toggleDarkMode} }>
      {children}
    </DarkModeContext.Provider>
  )
}


Enter fullscreen mode Exit fullscreen mode

On ajoute donc un objet avec ce que l'on souhaite rendre disponible.

3. Récupérer les données/fonctions de notre context

Est-ce que vous vous rappelez de ce que je vous ai dit plus haut ? Lorsque l'on souhaite obtenir quelque chose, on le demande gentiment. Ça fait partie des bonnes manières.

Pour obtenir ce que l'on souhaite, nous allons utiliser le Hook useContext. Il va nous permettre d'utiliser ce que Context à rendu disponible.

Avec cette ligne et grâce au destructuring, nous nous permettons de récupérer notre donnée et notre fonction renduent disponible par notre Context :
const {darkMode, toggleDarkMode} = useContext(DarkModeContext);

Maintenant que nous avons accès à notre fonction, nous allons l'ajouter et l'exécuter lorsque le bouton sera cliqué et pour vous montrer que cela fonctionne, nous allons loguer la valeur de darkMode.

Votre code devrait ressembler à ceci :



import { useContext } from "react"
import { DarkModeContext } from "./DarkModeProvider"

export default function ToggleButton() {
  const {darkMode, toggleDarkMode} = useContext(DarkModeContext);
  console.log(darkMode);
  return <button onClick={toggleDarkMode}>Toggle</button>
}


Enter fullscreen mode Exit fullscreen mode

Maintenant, ouvrez la console et cliquez sur sur le bouton et vous verrez la valeur de darkMode passer de false à true et ainsi de suite.

Super ! On a terminé toutes les étapes pour apprendre à utiliser les propriétés transmises par Context.

De ce fait, voici le code qui nous permet d'ajouter la classe dark-theme pour notre app :



import { useContext } from "react";
import Content from "./Content";
import { DarkModeContext } from "./DarkModeProvider";

export default function App() {
  const {darkMode} = useContext(DarkModeContext);
  return (
    <div className={`app ${darkMode && 'dark-theme'}`}>
        <Content />
    </div>
  )
}


Enter fullscreen mode Exit fullscreen mode

On récupère la valeur de darkMode et si elle est true, alors la classe sera ajouté.

Conclusion

Context nous permets de rendre disponible nos données/fonctions beaucoup plus facilement. On utilise Context généralement pour des actions occasionnels (changement de thème, changement de la langue du site, …).

Je vous invite maintenant à lire la documentation officielle de React sur Context et useContext pour parfaire vos connaissances et réaliser les exemples qu'ils proposent.

Sayonara !

💖 💪 🙅 🚩
ahmedbouras
Ahmed Bouras

Posted on April 1, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related