hydrateRoot

Nota bene

Questa pagina è stata tradotta automaticamente e supervisionata da un maintainer. Un’ulteriore revisione da parte della community sarebbe comunque utile. Migliora questa traduzione.

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.

Vedi altri esempi sotto.

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 metodo ReactDOM Server come renderToPipeableStream(<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’error catturato dal contenitore di errori e un oggetto errorInfo che contiene il componentStack.
    • optional onUncaughtError: Callback chiamata quando viene lanciato un errore e non viene catturato da un contenitore di errori. Viene chiamata con l’error lanciato e un oggetto errorInfo che contiene il componentStack.
    • optional onRecoverableError: Callback chiamata quando React recupera automaticamente dagli errori. Viene chiamata con un error lanciato da React e un oggetto errorInfo che contiene il componentStack. Alcuni errori recuperabili possono includere la causa originale dell’errore come error.cause.
    • optional identifierPrefix: Un prefisso stringa che React usa per gli ID generati da useId. 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 usa useActionState con un permalink, passa lo state del form risultante così che useActionState restituisca lo state inviato invece dell’initialState. Deve essere lo stesso valore del formState passato al renderer server. Di solito viene passato dal tuo framework.

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 hydrateRoot nella 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. Usa createRoot() 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.

Vedi altri esempi sotto.

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 con createElement(), una stringa, un numero, null o undefined.

Returns

root.render restituisce undefined.

Caveats

  • Se chiami root.render prima 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.unmount smonterà tutti i componenti nell’albero e “scollegherà” React dal nodo DOM root.

  • Una volta chiamato root.unmount non puoi chiamare di nuovo root.render sulla stessa root. Tentare di chiamare root.render su 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.

Insidia

L’albero React che passi a hydrateRoot deve produrre lo stesso output che aveva prodotto sul server.

Questo è importante per l’esperienza utente. L’utente passerà del tempo a guardare l’HTML generato dal server prima che il tuo codice JavaScript venga caricato. La renderizzazione lato server crea l’illusione che l’app si carichi più velocemente mostrando l’istantanea HTML del suo output. Mostrare all’improvviso contenuto diverso rompe quell’illusione. Per questo l’output della renderizzazione lato server deve corrispondere all’output della renderizzazione iniziale sul client.

Le cause più comuni che portano a errori di idratazione includono:

  • Spazi bianchi extra (come le newline) attorno all’HTML generato da React all’interno del nodo root.
  • Usare controlli come typeof window !== 'undefined' nella logica di renderizzazione.
  • Usare API disponibili solo nel browser come window.matchMedia nella logica di renderizzazione.
  • Renderizzare dati diversi sul server e sul client.

React recupera da alcuni errori di idratazione, ma devi correggerli come qualsiasi altro bug. Nel caso migliore, causeranno un rallentamento; nel caso peggiore, i gestori di eventi possono essere collegati agli elementi sbagliati.


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.

Insidia

Questo approccio rallenta l’idratazione perché i tuoi componenti devono renderizzare due volte. Tieni presente l’esperienza utente su connessioni lente. Il codice JavaScript può caricarsi molto più tardi rispetto alla renderizzazione HTML iniziale, quindi renderizzare un’UI diversa subito dopo l’idratazione può anche risultare brusco per l’utente.


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:

  1. L’error che è stato lanciato.
  2. 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(...):

Console
Warning: You passed a second argument to root.render(…) but it only accepts one argument.

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});