hydrateRoot
hydrateRoot
vous permet d’afficher des composants React dans un nœud DOM du navigateur dont le HTML a été préalablement généré par react-dom/server
.
const root = hydrateRoot(domNode, reactNode, options?)
- Référence
- Utilisation
- Hydrater du HTML généré côté serveur
- Hydrater un document entier
- Réduire au silence les erreurs d’hydratation incontournables
- Différencier les contenus côté client et côté serveur
- Mettre à jour un composant racine hydraté
- Show a dialog for uncaught errors
- Displaying Error Boundary errors
- Show a dialog for recoverable hydration mismatch errors
- Dépannage
Référence
hydrateRoot(domNode, reactNode, options?)
Appelez hydrateRoot
pour « attacher » React à du HTML existant préalablement généré par React dans un environnement serveur.
import { hydrateRoot } from 'react-dom/client';
const domNode = document.getElementById('root');
const root = hydrateRoot(domNode, reactNode);
React s’attachera au HTML existant à l’intérieur de domNode
, et prendra la main sur la gestion du DOM à l’intérieur. Une appli entièrement construite avec React n’aura généralement qu’un seul appel à hydrateRoot
, pour le composant racine.
Voir d’autres exemples ci-dessous.
Paramètres
-
domNode
: un élément DOM généré comme élément racine côté serveur. -
reactNode
: un nœud React utilisé pour afficher le HTML existant. Ce sera généralement un bout de JSX du genre<App />
, généré via une méthodereact-dom/server
telle querenderToPipeableStream(<App />)
. -
options
optionnelles : un objet avec des options pour la racine React.- Canary only optional
onCaughtError
: Callback called when React catches an error in an Error Boundary. Called with theerror
caught by the Error Boundary, and anerrorInfo
object containing thecomponentStack
. - Canary only optional
onUncaughtError
: Callback called when an error is thrown and not caught by an Error Boundary. Called with theerror
that was thrown, and anerrorInfo
object containing thecomponentStack
. onRecoverableError
optionnel : fonction de rappel appelée lorsque React retombe automatiquement sur ses pieds suite à une erreur. Appelée avec l’error
levée par React et un objeterrorInfo
contenant lacomponentStack
. Certaines de ces erreurs peuvent exposer leur cause originelle danserror.cause
.identifierPrefix
optionnel : un préfixe textuel utilisé pour les ID générés paruseId
. Pratique pour éviter les conflits entre les ID au sein de racines multiples sur une même page.
- Canary only optional
Valeur renvoyée
hydrateRoot
renvoie un objet avec deux méthodes : render
et unmount
.
Limitations
hydrateRoot()
s’attend à ce que le contenu affiché soit identique au contenu généré côté serveur. Vous devriez considérer tout écart comme un bug et le corriger.- En mode développement, React vous avertira de tout écart de correspondance durant l’hydratation. Vous n’avez aucune garantie que les différences d’attributs seront résolues. C’est important pour des raisons de performances parce que dans la plupart des applis, les écarts sont rares, aussi valider tout le balisage serait d’une lourdeur prohibitive.
- Vous n’aurez probablement qu’un seul appel à
hydrateRoot
dans votre appli. Si vous utilisez un framework, il le fait peut-être pour vous. - Si votre appli est entièrement côté client, sans HTML déjà généré par le serveur, appeler
hydrateRoot()
n’est pas autorisé. Utilisez plutôtcreateRoot()
.
root.render(reactNode)
Appelez root.render
pour mettre à jour un composant React au sein d’une racine React hydratée associée à un élément DOM du navigateur.
root.render(<App />);
React mettra à jour <App />
dans le root
hydraté.
Voir d’autres exemples ci-dessous.
Paramètres
reactNode
: un nœud React que vous souhaitez mettre à jour. Ce sera généralement un bout de JSX du genre<App />
, mais vous pouvez aussi passer un élément React créé aveccreateElement()
, une chaîne de caractères, un nombre,null
ouundefined
.
Valeur renvoyée
root.render
renvoie undefined
.
Limitations
- Si vous appelez
root.render
avant que la racine n’ait terminé son hydratation, React effacera tout le HTML produit par le serveur et basculera la racine entière vers un rendu côté client.
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.
Returns
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 rappelerroot.render
sur cette même racine. Tenter d’appelerroot.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).
Utilisation
Hydrater du HTML généré côté serveur
Si le HTML de votre appli est généré par react-dom/server
, vous devez l’hydrater côté client.
import { hydrateRoot } from 'react-dom/client';
hydrateRoot(document.getElementById('root'), <App />);
Ça hydratera le HTML issu du serveur au sein du nœud DOM du navigateur en utilisant le composant React de votre appli. En général, vous ne le ferez qu’une fois au démarrage. Si vous utilisez un framework, il le fait peut-être pour vous sous le capot.
Pour hydrater votre appli, React « attachera » la logique de vos composants au HTML initial généré par le serveur. L’hydratation transforme cet instantané initial du HTML, issu du serveur, en une appli pleinement interactive s’exécutant dans le navigateur.
import './styles.css'; import { hydrateRoot } from 'react-dom/client'; import App from './App.js'; hydrateRoot( document.getElementById('root'), <App /> );
Vous ne devriez pas avoir besoin de rappeler hydrateRoot
ou de l’appeler ailleurs. À partir de ce moment, React prendra la main sur le DOM de votre application. Pour mettre à jour l’interface utilisateur (UI), vos composants mettront plutôt à jour l’état.
Hydrater un document entier
Les applis entièrement construites avec React peuvent produire le document entier via leur JSX, y compris la balise <html>
:
function App() {
return (
<html>
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/styles.css"></link>
<title>Mon appli</title>
</head>
<body>
<Router />
</body>
</html>
);
}
Pour hydrater le document entier, passez la variable globale document
comme premier argument dans votre appel à hydrateRoot
:
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(document, <App />);
Réduire au silence les erreurs d’hydratation incontournables
Si pour un élément spécifique, un attribut ou le contenu textuel s’avère inévitablement différent entre le serveur et le client (un horodatage, par exemple), vous pouvez choisir de réduire au silence l’avertissement d’écart d’hydratation.
Pour éviter les avertissements d’hydratation sur un élément spécifique, ajoutez-lui la prop suppressHydrationWarning={true}
:
export default function App() { return ( <h1 suppressHydrationWarning={true}> Date actuelle : {new Date().toLocaleDateString()} </h1> ); }
Ça ne fonctionne qu’à un niveau de profondeur, et c’est vraiment une échappatoire. N’en abusez pas. React ne rattrapera le coup que pour les contenus textuels, il risque donc de rester quelques incohérences jusqu’au prochain rendu.
Différencier les contenus côté client et côté serveur
Si vous différenciez volontairement l’affichage entre le côté serveur et le côté client, vous pouvez faire un rendu en deux temps. Les composants qui affichent un contenu différent côté client peuvent lire une variable d’état telle que isClient
, que vous pouvez mettre à true
dans un Effet :
import { useState, useEffect } from "react"; export default function App() { const [isClient, setIsClient] = useState(false); useEffect(() => { setIsClient(true); }, []); return ( <h1> {isClient ? 'Côté client' : 'Côté serveur'} </h1> ); }
De cette façon, la passe initiale de rendu afficher le même contenu que côté serveur, évitant toute incohérence ; mais une passe supplémentaire surviendra de façon synchrone juste après l’hydratation.
Mettre à jour un composant racine hydraté
Après que la racine a terminé l’hydratation, vous pouvez appeler root.render
pour mettre à jour le composant React racine. Contrairement à createRoot
, vous n’avez pas besoin de faire ça car le contenu initial était déjà présent dans le HTML.
Si vous appelez root.render
après l’hydratation, et 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 { hydrateRoot } from 'react-dom/client'; import './styles.css'; import App from './App.js'; const root = hydrateRoot( document.getElementById('root'), <App counter={0} /> ); let i = 0; setInterval(() => { root.render(<App counter={i} />); i++; }, 1000);
Il est toutefois rare d’appeler root.render
sur une racine hydratée. En général, vos composants mettront plutôt à jour l’état.
Show a dialog for uncaught errors
By default, React will log all uncaught errors to the console. To implement your own error reporting, you can provide the optional onUncaughtError
root option:
import { hydrateRoot } from 'react-dom/client';
const root = hydrateRoot(
document.getElementById('root'),
<App />,
{
onUncaughtError: (error, errorInfo) => {
console.error(
'Uncaught error',
error,
errorInfo.componentStack
);
}
}
);
root.render(<App />);
The onUncaughtError option is a function called with two arguments:
- The error that was thrown.
- An errorInfo object that contains the componentStack of the error.
You can use the onUncaughtError
root option to display error dialogs:
import { hydrateRoot } from "react-dom/client"; import App from "./App.js"; import {reportUncaughtError} from "./reportError"; import "./styles.css"; import {renderToString} from 'react-dom/server'; const container = document.getElementById("root"); const root = hydrateRoot(container, <App />, { onUncaughtError: (error, errorInfo) => { if (error.message !== 'Known error') { reportUncaughtError({ error, componentStack: errorInfo.componentStack }); } } });
Displaying Error Boundary errors
By default, React will log all errors caught by an Error Boundary to console.error
. To override this behavior, you can provide the optional onCaughtError
root option for errors caught by an Error Boundary:
import { hydrateRoot } from 'react-dom/client';
const root = hydrateRoot(
document.getElementById('root'),
<App />,
{
onCaughtError: (error, errorInfo) => {
console.error(
'Caught error',
error,
errorInfo.componentStack
);
}
}
);
root.render(<App />);
The onCaughtError option is a function called with two arguments:
- The error that was caught by the boundary.
- An errorInfo object that contains the componentStack of the error.
You can use the onCaughtError
root option to display error dialogs or filter known errors from logging:
import { hydrateRoot } from "react-dom/client"; import App from "./App.js"; import {reportCaughtError} from "./reportError"; import "./styles.css"; const container = document.getElementById("root"); const root = hydrateRoot(container, <App />, { onCaughtError: (error, errorInfo) => { if (error.message !== 'Known error') { reportCaughtError({ error, componentStack: errorInfo.componentStack }); } } });
Show a dialog for recoverable hydration mismatch errors
When React encounters a hydration mismatch, it will automatically attempt to recover by rendering on the client. By default, React will log hydration mismatch errors to console.error
. To override this behavior, you can provide the optional onRecoverableError
root option:
import { hydrateRoot } from 'react-dom/client';
const root = hydrateRoot(
document.getElementById('root'),
<App />,
{
onRecoverableError: (error, errorInfo) => {
console.error(
'Caught error',
error,
error.cause,
errorInfo.componentStack
);
}
}
);
The onRecoverableError option is a function called with two arguments:
- The error React throws. Some errors may include the original cause as error.cause.
- An errorInfo object that contains the componentStack of the error.
You can use the onRecoverableError
root option to display error dialogs for hydration mismatches:
import { hydrateRoot } from "react-dom/client"; import App from "./App.js"; import {reportRecoverableError} from "./reportError"; import "./styles.css"; const container = document.getElementById("root"); const root = hydrateRoot(container, <App />, { onRecoverableError: (error, errorInfo) => { reportRecoverableError({ error, cause: error.cause, componentStack: errorInfo.componentStack }); } });
Dépannage
J’ai une erreur : “You passed a second argument to root.render”
A common mistake is to pass the options for hydrateRoot
to root.render(...)
:
To fix, pass the root options to hydrateRoot(...)
, not root.render(...)
:
// 🚩 Wrong: root.render only takes one argument.
root.render(App, {onUncaughtError});
// ✅ Correct: pass options to createRoot.
const root = hydrateRoot(container, <App />, {onUncaughtError});