hydrateRoot
hydrateRoot ti permette di visualizzare componenti React all’interno di un nodo DOM del browser il cui contenuto HTML è stato generato in precedenza da react-dom/server.
const root = hydrateRoot(domNode, reactNode, options?)Reference
hydrateRoot(domNode, reactNode, options?)
Chiama hydrateRoot per “collegare” React all’HTML esistente che era già stato renderizzato da React in un ambiente server.
import { hydrateRoot } from 'react-dom/client';
const domNode = document.getElementById('root');
const root = hydrateRoot(domNode, reactNode);React si collegherà all’HTML che esiste all’interno del domNode e prenderà in carico la gestione del DOM al suo interno. Un’app interamente costruita con React avrà di solito una sola chiamata a hydrateRoot con il suo componente root.
Parameters
-
domNode: Un elemento DOM che era stato renderizzato come elemento root sul server. -
reactNode: Il nodo React usato per renderizzare l’HTML esistente. Di solito sarà un pezzo di JSX come<App />che era stato renderizzato con un metodoReactDOM ServercomerenderToPipeableStream(<App />). -
optional
options: Un oggetto con opzioni per questa root React.- optional
onCaughtError: Callback chiamata quando React cattura un errore in un contenitore di errori. Viene chiamata con l’errorcatturato dal contenitore di errori e un oggettoerrorInfoche contiene ilcomponentStack. - optional
onUncaughtError: Callback chiamata quando viene lanciato un errore e non viene catturato da un contenitore di errori. Viene chiamata con l’errorlanciato e un oggettoerrorInfoche contiene ilcomponentStack. - optional
onRecoverableError: Callback chiamata quando React recupera automaticamente dagli errori. Viene chiamata con unerrorlanciato da React e un oggettoerrorInfoche contiene ilcomponentStack. Alcuni errori recuperabili possono includere la causa originale dell’errore comeerror.cause. - optional
identifierPrefix: Un prefisso stringa che React usa per gli ID generati dauseId. Utile per evitare conflitti quando usi più root sulla stessa pagina. Deve essere lo stesso prefisso usato sul server. - optional
formState: Lo state del form da un invio di form gestito da una Server Function. Se la pagina è stata renderizzata sul server in risposta all’invio di un form che usauseActionStatecon unpermalink, passa lo state del form risultante così cheuseActionStaterestituisca lo state inviato invece dell’initialState. Deve essere lo stesso valore delformStatepassato al renderer server. Di solito viene passato dal tuo framework.
- optional
Returns
hydrateRoot restituisce un oggetto con due metodi: render e unmount.
Caveats
hydrateRoot()si aspetta che il contenuto renderizzato sia identico al contenuto renderizzato lato server. Dovresti trattare le discrepanze come bug e correggerle.- In modalità development, React avvisa sulle discrepanze durante l’idratazione. Non ci sono garanzie che le differenze negli attributi verranno corrette in caso di discrepanze. Questo è importante per motivi di performance perché nella maggior parte delle app le discrepanze sono rare, e quindi validare tutto il markup sarebbe proibitivamente costoso.
- Probabilmente avrai una sola chiamata a
hydrateRootnella tua app. Se usi un framework, potrebbe eseguire questa chiamata per te. - Se la tua app è renderizzata lato client senza HTML già renderizzato, l’uso di
hydrateRoot()non è supportato. UsacreateRoot()al suo posto.
root.render(reactNode)
Chiama root.render per aggiornare un componente React all’interno di una root React idratata per un elemento DOM del browser.
root.render(<App />);React aggiornerà <App /> nella root idratata.
Parameters
reactNode: Un nodo React che vuoi aggiornare. Di solito sarà un pezzo di JSX come<App />, ma puoi anche passare un elemento React costruito concreateElement(), una stringa, un numero,nulloundefined.
Returns
root.render restituisce undefined.
Caveats
- Se chiami
root.renderprima che la root abbia finito di idratare, React cancellerà il contenuto HTML esistente renderizzato lato server e passerà l’intera root alla renderizzazione lato client.
root.unmount()
Chiama root.unmount per distruggere un albero renderizzato all’interno di una root React.
root.unmount();Un’app interamente costruita con React di solito non avrà chiamate a root.unmount.
È soprattutto utile se il nodo DOM della tua root React (o uno dei suoi antenati) può essere rimosso dal DOM da altro codice. Ad esempio, immagina un pannello a schede jQuery che rimuove le schede inattive dal DOM. Se una scheda viene rimossa, tutto al suo interno (incluse le root React al suo interno) verrebbe rimosso dal DOM. In quel caso, devi dire a React di “smettere” di gestire il contenuto della root rimossa chiamando root.unmount. Altrimenti, i componenti all’interno della root rimossa non saprebbero di dover fare pulizia e liberare risorse globali come le sottoscrizioni.
Chiamare root.unmount smonterà tutti i componenti nella root e “scollegherà” React dal nodo DOM root, inclusa la rimozione dei gestori di eventi e dello state nell’albero.
Parameters
root.unmount non accetta parametri.
Returns
root.unmount restituisce undefined.
Caveats
-
Chiamare
root.unmountsmonterà tutti i componenti nell’albero e “scollegherà” React dal nodo DOM root. -
Una volta chiamato
root.unmountnon puoi chiamare di nuovoroot.rendersulla stessa root. Tentare di chiamareroot.rendersu una root smontata lancerà un errore “Cannot update an unmounted root”.
Usage
Idratare HTML renderizzato lato server
Se l’HTML della tua app è stato generato da react-dom/server, devi idratarlo sul client.
import { hydrateRoot } from 'react-dom/client';
hydrateRoot(document.getElementById('root'), <App />);Questo idraterà l’HTML del server all’interno del nodo DOM del browser con il componente React della tua app. Di solito, lo fai una sola volta all’avvio. Se usi un framework, potrebbe farlo dietro le quinte per te.
Per idratare la tua app, React “collegherà” la logica dei tuoi componenti all’HTML iniziale generato dal server. L’idratazione trasforma l’istantanea HTML iniziale dal server in un’app completamente interattiva che gira nel browser.
import './styles.css'; import { hydrateRoot } from 'react-dom/client'; import App from './App.js'; hydrateRoot( document.getElementById('root'), <App /> );
Non dovresti aver bisogno di chiamare di nuovo hydrateRoot o di chiamarlo in più punti. Da questo momento in poi, React gestirà il DOM della tua applicazione. Per aggiornare l’UI, i tuoi componenti useranno lo state al suo posto.
Idratare un intero documento
Le app interamente costruite con React possono renderizzare l’intero documento come JSX, incluso il tag <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>My app</title>
</head>
<body>
<Router />
</body>
</html>
);
}Per idratare l’intero documento, passa la variabile globale document come primo argomento a hydrateRoot:
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(document, <App />);Sopprimere errori inevitabili di discrepanza nell’idratazione
Se l’attributo o il contenuto testuale di un singolo elemento è inevitabilmente diverso tra server e client (ad esempio, un timestamp), puoi silenziare l’avviso di discrepanza nell’idratazione.
Per silenziare gli avvisi di idratazione su un elemento, aggiungi suppressHydrationWarning={true}:
export default function App() { return ( <h1 suppressHydrationWarning={true}> Current Date: {new Date().toLocaleDateString()} </h1> ); }
Funziona solo a un livello di profondità ed è pensato come via di fuga. Non abusarne. React non tenterà di correggere il contenuto testuale non corrispondente.
Gestire contenuto diverso tra client e server
Se hai intenzionalmente bisogno di renderizzare qualcosa di diverso sul server e sul client, puoi fare una renderizzazione in due passaggi. I componenti che renderizzano qualcosa di diverso sul client possono leggere una variabile di state come isClient, che puoi impostare su true in un Effetto:
import { useState, useEffect } from "react"; export default function App() { const [isClient, setIsClient] = useState(false); useEffect(() => { setIsClient(true); }, []); return ( <h1> {isClient ? 'Is Client' : 'Is Server'} </h1> ); }
In questo modo il passaggio di renderizzazione iniziale renderizzerà lo stesso contenuto del server, evitando le discrepanze, ma un passaggio aggiuntivo avverrà in modo sincrono subito dopo l’idratazione.
Usa questo approccio quando vuoi che il contenuto renderizzato sul client sia diverso dall’HTML iniziale renderizzato lato server.
Se un componente deve renderizzare solo nel browser, chiama use(browser()) invece di aspettare un Effetto.
Aggiornare un componente root idratato
Dopo che la root ha finito di idratare, puoi chiamare root.render per aggiornare il componente React root. A differenza di createRoot, di solito non devi farlo perché il contenuto iniziale era già stato renderizzato come HTML.
Se chiami root.render in un momento successivo all’idratazione, e la struttura dell’albero dei componenti corrisponde a quanto renderizzato in precedenza, React preserverà lo state. Nota come puoi digitare nell’input, il che significa che gli aggiornamenti dalle ripetute chiamate a render ogni secondo in questo esempio non sono distruttivi:
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);
È poco comune chiamare root.render su una root idratata. Di solito, aggiornerai lo state all’interno di uno dei componenti al suo posto.
Registrazione degli errori in produzione
Per impostazione predefinita, React registrerà tutti gli errori nella console. Per implementare la tua segnalazione errori, puoi fornire le opzioni root opzionali per i gestori di errori onUncaughtError, onCaughtError e onRecoverableError:
import { hydrateRoot } from "react-dom/client";
import App from "./App.js";
import { reportCaughtError } from "./reportError";
const container = document.getElementById("root");
const root = hydrateRoot(container, <App />, {
onCaughtError: (error, errorInfo) => {
if (error.message !== "Known error") {
reportCaughtError({
error,
componentStack: errorInfo.componentStack,
});
}
},
});L’opzione onCaughtError è una funzione chiamata con due argomenti:
- L’error che è stato lanciato.
- Un oggetto errorInfo che contiene il componentStack dell’errore.
Insieme a onUncaughtError e onRecoverableError, puoi implementare il tuo sistema di segnalazione errori:
import { hydrateRoot } from "react-dom/client"; import App from "./App.js"; import { onCaughtErrorProd, onRecoverableErrorProd, onUncaughtErrorProd, } from "./reportError"; const container = document.getElementById("root"); hydrateRoot(container, <App />, { // Tieni presente di rimuovere queste opzioni in development per sfruttare // i gestori predefiniti di React o implementare il tuo overlay per development. // I gestori sono specificati incondizionatamente qui solo a scopo dimostrativo. onCaughtError: onCaughtErrorProd, onRecoverableError: onRecoverableErrorProd, onUncaughtError: onUncaughtErrorProd, });
Troubleshooting
Ricevo un errore: “You passed a second argument to root.render”
Un errore comune è passare le opzioni per hydrateRoot a root.render(...):
Per risolvere, passa le opzioni root a hydrateRoot(...), non a root.render(...):
// 🚩 Sbagliato: root.render accetta un solo argomento.
root.render(App, {onUncaughtError});
// ✅ Corretto: passa le opzioni a hydrateRoot.
const root = hydrateRoot(container, <App />, {onUncaughtError});