createRoot vous permet de créer une racine de rendu pour afficher vos composants React dans un nœud DOM du navigateur.

const root = createRoot(domNode, options?)

Référence

createRoot(domNode, options?)

Appelez createRoot pour créer une racine de rendu React afin d’afficher du contenu dans un élément DOM du navigateur.

import { createRoot } from 'react-dom/client';

const domNode = document.getElementById('root');
const root = createRoot(domNode);

React créera une racine de rendu associée au domNode, puis prendra la main sur la gestion de son DOM. Une fois la racine créée, vous devrez appeler root.render pour afficher un composant React à l’intérieur :

root.render(<App />);

Une appli entièrement construite en React n’aura généralement qu’un appel à createRoot pour son composant racine. Une page qui « saupoudre » du React dans certaines de ses parties peut avoir autant de racines distinctes que nécessaire.

Voir d’autres exemples ci-dessous.

Paramètres

  • domNode : un élément DOM. React créera une racine de rendu pour cet élément DOM et vous permettra d’appeler des méthodes sur cette racine, telles que render pour afficher le contenu produit par React.

  • options optionnelles : un objet avec des options pour la racine React.

    • onRecoverableError optionnel : fonction de rappel appelée lorsque React retombe automatiquement sur ses pieds suite à une erreur.
    • identifierPrefix optionnel : un préfixe textuel utilisé pour les ID générés par useId. Pratique pour éviter les conflits entre les ID au sein de racines multiples sur une même page.

Valeur renvoyée

createRoot renvoie un objet avec deux méthodes : render et unmount.

Limitations

  • Si votre appli bénéficie d’un premier rendu côté serveur, vous ne pourrez pas utiliser createRoot() : utilisez plutôt hydrateRoot().
  • Vous n’aurez probablement qu’un seul appel à createRoot dans votre appli. Si vous utilisez un framework, il le fait peut-être pour vous.
  • Lorsque vous souhaitez afficher un bout de JSX dans une autre partie du DOM, une partie qui n’est pas un enfant de votre composant (par exemple pour une boîte de dialogue modale ou une infobulle), utilisez createPortal plutôt que createRoot.

root.render(reactNode)

Appelez root.render pour afficher un bout de JSX (un « nœud React ») dans le nœud DOM du navigateur associé à la racine React.

root.render(<App />);

React affichera <App /> dans le root, et prendra la main sur la gestion du DOM à l’intérieur.

Voir d’autres exemples ci-dessous.

Paramètres

  • reactNode : un nœud React que vous souhaitez afficher. Ce sera généralement un bout de JSX du genre <App />, mais vous pouvez aussi passer un élément React créé avec createElement(), une chaîne de caractères, un nombre, null ou undefined.

Valeur renvoyée

root.render renvoie undefined.

Limitations

  • La première fois que vous appellez root.render, React videra tout le HTML existant au sein de la racine avant de faire le rendu du composant React à l’intérieur

  • Si le nœud DOM de votre racine contient du HTML généré par React côté serveur ou lors du build, utilisez plutôt hydrateRoot(), qui se contentera d’attacher les gestionnaires d’événements au HTML existant.

  • Si vous appelez render sur la même racine plusieurs fois, React mettra à jour le DOM si nécessaire pour refléter le dernier JSX que vous lui avez passé. React décidera quelles parties du DOM réutiliser et lesquelles nécessitent une création à froid en « examinant la correspondance » entre l’arbre React et celui du précédent rendu. Appeler render à nouveau sur la même racine est similaire à un appel de fonction set sur le composant racine : React évite les mises à jour DOM superflues.


root.unmount()

Appelez root.unmount pour détruire l’arborescence de rendu au sein d’une racine React.

root.unmount();

Une appli entièrement construite avec React n’appellera généralement pas root.unmount.

C’est principalement utile si le nœud DOM de votre racine React (ou un de ses ancêtres) est susceptible d’être retiré du DOM par du code tiers. Imaginez par exemple une gestion d’onglet basée sur jQuery qui retire les onglets inactifs du DOM. Si un onglet est retiré, tout ce qu’il contient (y compris d’éventuelles racines React) sera également retiré du DOM. Dans un tel cas, vous devez dire à React de « cesser » de gérer le contenu de la racine retirée en appelant root.unmount. Si vous ne le faisiez pas, les composants au sein de la racine retirée ne pourraient pas être nettoyés et libérer leurs ressources globales, telles que des abonnements.

Un appel à root.unmount démontera tous les composants dans cette racine et « détachera » React du nœud DOM racine, y compris pour la gestion événementielle et les états de l’arbre.

Paramètres

root.unmount ne prend aucun paramètre.

Valeur renvoyée

root.unmount renvoie undefined.

Limitations

  • Appeler root.unmount démontera tous les composants dans cette racine et « détachera » React du nœud DOM racine.

  • Une fois que vous avez appelé root.unmount, vous ne pouvez plus rappeler root.render sur cette même racine. Tenter d’appeler root.render sur une racine démontée lèvera une erreur “Cannot update an unmounted root” (« Impossible de mettre à jour une racine démontée », NdT). En revanche, vous pouvez créer une nouvelle racine pour le même nœud DOM une fois la racine précédente pour ce nœud démontée.


Utilisation

Afficher une appli entièrement construite avec React

Si votre appli est entièrement construite avec React, créez une racine unique pour l’appli complète.

import { createRoot } from 'react-dom/client';

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

En général, vous n’aurez besoin de ce code qu’une fois, au démarrage. Il va :

  1. Trouver le nœud DOM du navigateur défini dans votre HTML.
  2. Afficher le composant React de votre appli à l’intérieur.
import { createRoot } from 'react-dom/client';
import App from './App.js';
import './styles.css';

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

Si votre appli est entièrement construite avec React, vous ne devriez pas avoir besoin de créer davantage de racines, ni de rappeler root.render.

À partir de là, React gèrera le DOM de votre appli entière. Pour ajouter d’autres composants, imbriquez-les dans le composant App. Si vous avez besoin de mettre à jour l’interface utilisateur (UI), chaque composant peut le faire en utilisant l’état. Si vous souhaitez afficher du contenu complémentaire (comme une boîte de dialogue modale ou une infobulle) hors du nœud DOM, affichez-le dans un portail.

Remarque

Lorsque votre HTML est vide, l’utilisateur voit une page vierge jusqu’à ce que le code JavaScript soit chargé et exécuté :

<div id="root"></div>

Ça peut sembler très lent ! Pour remédier à ça, vous pouvez générer le HTML initial de vos composants côté serveur ou lors du build. Ainsi vos visiteurs pourront lire le texte, regarder les images, et cliquer sur les liens en attendant que votre code JavaScript soit chargé. Nous vous conseillons d’utiliser un framework qui propose ce genre d’optimisations d’entrée de jeu. En fonction de son approche, il pourra s’agir de rendu côté serveur (SSR pour server-side rendering, NdT) ou de génération de site statique (SSG pour static-site generation, NdT).

Piège

Les applis utilisant le rendu côté serveur ou la génération de site statique doivent appeler hydrateRoot plutôt que createRoot. React hydratera (réutilisera) alors les nœuds DOM de votre HTML plutôt que de les détruire pour les recréer ensuite.


Afficher une page partiellement construite avec React

Si votre page n’est pas entièrement construite avec React, vous pouvez appeler createRoot plusieurs fois, pour créer une racine de rendu pour chaque bloc d’UI géré par React. Vous pouvez alors afficher les contenus de votre choix dans chaque racine en appelantroot.render.

Dans l’exemple ci-dessous, deux composants React distincts sont affichés dans deux nœuds DOM définis dans le fichier index.html :

import './styles.css';
import { createRoot } from 'react-dom/client';
import { Comments, Navigation } from './Components.js';

const navDomNode = document.getElementById('navigation');
const navRoot = createRoot(navDomNode);
navRoot.render(<Navigation />);

const commentDomNode = document.getElementById('comments');
const commentRoot = createRoot(commentDomNode);
commentRoot.render(<Comments />);

Vous pourriez aussi créer un nouveau nœud DOM avec document.createElement() et l’ajouter manuellement au document.

const domNode = document.createElement('div');
const root = createRoot(domNode);
root.render(<Comment />);
document.body.appendChild(domNode); // Vous pouvez l’ajouter où bon vous semble

Pour retirer l’arbre React d’un nœud DOM et en nettoyer les ressources, appelez root.unmount.

root.unmount();

C’est surtout utile pour les composants React figurant au sein d’une appli écrite avec un autre framework.


Mettre à jour un composant racine

Vous pouvez appeler render plus d’une fois sur la même racine. Tant que la structure de l’arbre de composants correspond à celle déjà en place, React préservera l’état. Voyez comme vous pouvez taper quelque chose dans le champ, ce qui montre bien que les mises à jour issues d’appels répétés à render ne sont pas destructrices :

import { createRoot } from 'react-dom/client';
import './styles.css';
import App from './App.js';

const root = createRoot(document.getElementById('root'));

let i = 0;
setInterval(() => {
  root.render(<App counter={i} />);
  i++;
}, 1000);

Il est toutefois rare d’appeler render plusieurs fois. En général, vos composants mettront plutôt à jour l’état.


Dépannage

J’ai créé une racine mais rien ne s’affiche

Assurez-vous de ne pas oublier d’afficher effectivement votre appli (avec render) au sein de la racine :

import { createRoot } from 'react-dom/client';
import App from './App.js';

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

Tant que vous ne le faites pas, rien ne sera affiché.


J’ai une erreur : “Target container is not a DOM element”

(« Le conteneur cible n’est pas un élément DOM », NdT)

Cette erreur signifique que ce que vous avez passé à createRoot n’est pas un élément DOM.

Si vous ne comprenez pas bien ce qui se passe, essayer d’afficher des informations dans la console :

const domNode = document.getElementById('root');
console.log(domNode); // ???
const root = createRoot(domNode);
root.render(<App />);

Si par exemple domNode est null, ça signifie que getElementById a renvoyé null. Ça arrive lorsqu’aucun nœud du document n’a l’ID spécifié au moment de l’appel. Il peut y avoir plusieurs raisons à ça :

  1. L’ID que vous utilisez n’est pas tout à fait celui utilisé dans le HTML. Vérifiez les fautes de frappe !
  2. La balise <script> de votre bundle, si elle est synchrone (cas par défaut), ne peut pas « voir » les nœuds DOM qui apparaissent après elle dans le HTML.

Il est aussi fréquent d’obtenir cette erreur en écrivant par mégarde createRoot(<App />) plutôt que createRoot(domNode).


J’ai une erreur : “Functions are not valid as a React child.”

(« Les fonctions ne constituent pas des enfants React valides », NdT)

Cette erreur signifie que ce que vous avez passé à root.render n’est pas un composant React.

Ça peut arriver si vous appelez root.render en lui passant Component plutôt que <Component /> :

// 🚩 Erroné : App est une function, pas un composant.
root.render(App);

// ✅ Correct : <App /> est un composant.
root.render(<App />);

Ou si vous passez une fonction à root.render, plutôt que le résultat de l’appel à cette fonction :

// 🚩 Erroné : createApp est une fonction, pas un composant.
root.render(createApp);

// ✅ Correct : appeler createApp renvoie un composant.
root.render(createApp());

Mon HTML produit côté serveur est recréé de zéro

Si votre appli utilise le rendu côté serveur et inclut le HTML initial généré par React, vous remarquerez peut-être qu’en créant une racine pour appeler root.render, ça supprime tout ce HTML et re-crée les nœuds DOM de zéro. Ça peut être plus lent, mais surtout risque de réinitialiser le focus et la position de défilement tout en perdant les saisies de l’utilisateur.

Les applis qui font un rendu côté serveur doivent utiliser hydrateRoot plutôt que createRoot :

import { hydrateRoot } from 'react-dom/client';
import App from './App.js';

hydrateRoot(
document.getElementById('root'),
<App />
);

Remarquez que l’API est différente. En particulier, il n’y aura généralement pas d’appel ultérieur à root.render.