Créer des applications mobiles avec React Native

Auteur: Mohamed CHINY Durée necessaire pour le cours de Créer des applications mobiles avec React Native Niveau recommandé pour le cours de Créer des applications mobiles avec React Native Supports vidéo non disponibles pour ce cours Exercices de renforcement non disponibles pour ce cours Quiz non disponibles pour ce cours

Page 17: Gestion d'état global avec createContext et useContext

Toutes les pages

Context en React Native: Simplifier la communication entre composants

Dans la leçon consacrée à la personnalisation des composants importés avec les props, on a vu que ces deriners permettent de transmettre des informations d'un composant parent à un composant enfant. Ce qui est très pratique quand on veut réutiliser un composant tout en modifiant son comportement. Cependant, si l'enfant à qui on veut transmettre l'information se trouve trop loin dans l'arborescence (profondément imbriqué), alors la gestion des props devient trop compliquée, et c'est ce qu'on l'appelle le prop drilling.

C'est quoi le prop drilling?

Le prop drilling désigne le fait de faire transiter des données de composant en composant, même lorsque certains d’entre eux n’en ont pas réellement besoin. Dans une application React Native, cela arrive souvent lorsqu’un état global (comme un thème, un utilisateur connecté ou une configuration) doit être accessible à un composant profondément imbriqué. On se retrouve alors à passer des props intermédiaires uniquement pour atteindre la bonne destination, ce qui alourdit la structure et rend le code moins lisible.

Voyons ce code (simplifié):
// App.js
export default function App() {
   const message = "Bonjour depuis App !";

   return (
      <Parent message={message} />
   );
}

// Parent.js
function Parent({ message }) {
   return (
      <Child message={message} />
   );
}

// Child.js
function Child({ message }) {
   return (
      <GrandChild message={message} />
   );
}

// GrandChild.js
function GrandChild({ message }) {
   return (
      <Text>{message}</Text>
   );
}

Ce code illustre le prop drilling. En effet, une donnée définie dans App est transmise de composant en composant même si certains ne l’utilisent pas directement. Chaque niveau intermédiaire doit recevoir la prop puis la renvoyer, uniquement pour permettre à GrandChild d’y accéder. Cette chaîne de transmission rend l’architecture plus lourde et moins maintenable à mesure que l’application grandit, car chaque modification de la structure des composants impose de revoir la chaîne de props. Ainsi, le risque d’erreurs ou d'oubli augmente.

C’est précisément pour éviter cette complexité que la Context API a été introduite. Elle permet de partager des données globales sans passer par ces relais inutiles, rendant l’architecture plus propre, plus stable et plus facile à faire évoluer.

Mettre en place un Provider et un Consumer avec createContext et useContext

La Context API repose sur deux éléments clés: createContext qui permet de créer un espace partagé pour stocker un état ou une logique, et le Provider qui expose ces données à toute une portion de l’arborescence. En enveloppant une partie de l’application avec un Provider, on définit la zone dans laquelle les composants pourront accéder aux informations partagées sans avoir à transmettre des props manuellement. C’est la première étape pour mettre en place un état global léger et éviter le prop drilling.

Le hook useContext intervient ensuite comme un moyen simple et direct de consommer ces données dans n’importe quel composant enfant du Provider. Au lieu de passer par une chaîne de props, useContext permet d’accéder immédiatement à la valeur du contexte, rendant le code plus lisible et plus concis. Donc, createContext, le Provider et useContext forment un mécanisme fluide pour partager des informations globales dans une application React Native moderne.

Imaginons que l’on veuille transmettre le libellé d’un bouton depuis le composant principal App. Ce bouton se trouve dans un composant enfant nommé Button que l’on importe.

Le code du composant principal App ressemblera à ceci:
import { View, StyleSheet, Button } from 'react-native';
import { createContext } from 'react';
import MyButton from './components/MyButton';

export const label=createContext(null)

export default function App() {
   return (
      <View style={styles.container}>
         <label.Provider
         value="Presser pour continuer">
            <MyButton />
         </label.Provider>
      </View>
   );
}

const styles=StyleSheet.create({
   container:{
      flex:1,
      justifyContent:"center",
      alignItems:"center"
   }
})

Ce code crée un contexte nommé label grâce à createContext, puis utilise son Provider pour rendre une valeur accessible à tous les composants enfants. Dans App, le Provider enveloppe MyButton (qui représente le composant importé) et lui transmet la chaîne "Presser pour continuer" sans passer par des props classiques. Ainsi, n’importe quel composant situé à l’intérieur du Provider (MyButton dans ce cas) pourra récupérer cette valeur via useContext(label) (que l'on invoquera dans le composant MyButton) ce qui évite le prop drilling et centralise la donnée au même endroit.
Vous avez certainement remarqué l'exportation du contexte label. C'est pour qu'il soit accessible depuis d’autres fichiers afin que les composants puissent l’importer et l’utiliser.
Maintenant voyons le code du composant importé MyButton
import { Button } from 'react-native'
import { useContext } from 'react'
import { label } from '../App'
export default function MyButton(){
   const value=useContext(label)
   return(
      <Button title={value} />
   )
}
Le composant MyButton récupère la valeur du contexte label grâce au hook useContext, ce qui lui permet d’accéder directement au texte fourni par le Provider dans App. Une fois cette valeur extraite, elle est utilisée comme titre du bouton via la proprité title. Ainsi, le composant n’a pas besoin de recevoir une prop manuellement, mais il lit simplement la donnée partagée dans le contexte, ce qui rend le code plus propre et évite le prop drilling.
Je vous invite à consulter cette leçon sur l’utilisation du Context en React pour approfondir le sujet. Le fonctionnement est exactement le même en React Native, les concepts et la logique restant inchangés.