Initialisation des systèmes...

Baptiste.Dev
Retour aux notes
FrameworksIntermédiaireSérie : React / Next.js

React : La communication entre composants

Comment les composants échangent des données : le flux descendant des props, les callbacks pour remonter l'information, le lifting state up entre frères, et le Context pour éviter le prop drilling.

Par Baptiste Vidal
4 min de lecture
Mis à jour il y a 2 semaines
reactcommunicationlifting-statecontextfrontend

React : La communication entre composants

Jusqu'ici, chaque composant gérait son propre coin de state. Mais une vraie application est un arbre de composants qui doivent s'échanger des données. Comment un enfant prévient-il son parent ? Comment deux frères partagent-ils la même info ? C'est tout l'objet de cette note.


# Le flux des données est descendant

Règle de base de React : les données circulent du parent vers l'enfant, via les props. C'est un flux unidirectionnel (one-way data flow) : l'enfant reçoit, il ne remonte rien tout seul.

Pour envoyer une information vers le haut (enfant → parent), le parent passe une fonction en prop. L'enfant l'appelle ; c'est le parent qui décide quoi en faire.

function Parent() {
  function gererClicEnfant(message) {
    console.log("L'enfant a dit :", message);
  }
  return <Enfant onAction={gererClicEnfant} />;
}
 
function Enfant({ onAction }) {
  return <button onClick={() => onAction("coucou")}>Envoyer</button>;
}

Les données descendent (props), les événements remontent (callbacks). Ce sont les deux seuls sens de circulation.


# Faire remonter le state (lifting state up)

Que faire quand deux frères ont besoin de la même donnée ? Un composant ne peut pas lire le state d'un autre. La solution : déplacer le state vers leur plus proche ancêtre commun, puis le redistribuer en props.

function Recherche() {
  const [texte, setTexte] = useState(""); // le state vit dans le parent
 
  return (
    <>
      <ChampRecherche valeur={texte} onChanger={setTexte} />
      <Resultat texte={texte} />
    </>
  );
}
 
function ChampRecherche({ valeur, onChanger }) {
  return <input value={valeur} onChange={(e) => onChanger(e.target.value)} />;
}
 
function Resultat({ texte }) {
  return <p>Tu cherches : {texte}</p>;
}

Le state est remonté dans Recherche. ChampRecherche le modifie (callback), Resultat le lit (prop). Les deux frères sont synchronisés sans se parler directement : ils passent par le parent. C'est le patron le plus courant pour partager un état.


# Le problème : le prop drilling

Le lifting state up marche bien... tant que l'ancêtre commun est proche. Mais si la donnée doit descendre à travers beaucoup de niveaux, on se retrouve à faire suivre une prop à des composants intermédiaires qui ne s'en servent même pas, juste pour la transmettre plus bas.

App (theme)
 └── Layout        (reçoit theme, ne l'utilise pas, le passe)
      └── Sidebar  (reçoit theme, ne l'utilise pas, le passe)
           └── Bouton  (utilise enfin theme)

Ce « tuyautage » de props à travers l'arbre s'appelle le prop drilling. C'est verbeux et fragile. Pour les données vraiment transverses, React propose une autre voie.


# Le Context : partager sans faire suivre

Le Context permet à un composant de mettre une valeur à disposition de tous ses descendants, sans la passer de main en main. Trois étapes :

import { createContext, useContext } from "react";
 
// 1. Créer le contexte (avec une valeur par défaut)
const ThemeContext = createContext("clair");
 
// 2. Fournir une valeur, en haut de l'arbre
function App() {
  return (
    <ThemeContext.Provider value="sombre">
      <Layout />
    </ThemeContext.Provider>
  );
}
 
// 3. Consommer, n'importe où en dessous - sans prop intermédiaire
function Bouton() {
  const theme = useContext(ThemeContext);
  return <button className={theme}>OK</button>;
}

Layout et Sidebar n'ont plus rien à transmettre : Bouton lit directement le thème via useContext. Le prop drilling disparaît.


# Context : à utiliser avec parcimonie

Le Context est tentant, mais ce n'est pas une solution universelle :

  • Quand la valeur du Provider change, tous les composants qui la consomment se re-rendent. À réserver aux données qui changent peu.
  • Ce n'est pas un gestionnaire d'état global (comme Redux ou Zustand) : il transporte une valeur, il n'organise pas la logique.

En pratique, il brille pour le thème, l'utilisateur connecté, la langue - des données globales et stables. Pour du partage local entre quelques composants, le lifting state up vu plus haut reste le bon réflexe.


# À retenir

  • Le flux de données est descendant (props) ; pour remonter, le parent passe une fonction que l'enfant appelle.
  • Lifting state up : deux frères partagent un état en le remontant vers leur ancêtre commun.
  • Le prop drilling (faire suivre une prop à travers des couches inutiles) est le signal qu'on a besoin d'autre chose.
  • Le Context partage une valeur avec tous les descendants sans la faire suivre - mais se réserve aux données globales et stables (thème, auth, langue).

Prochaine étape : on quitte le pur React côté client pour aborder ce qui fait la force de Next.js - les Server Components et le rendu côté serveur.