hydrateRoot
hydrateRoot
permite que você integre componentes React em um nó no DOM do navegador, cujo conteúdo HTML foi previamente gerado por react-dom/server
.
const root = hydrateRoot(domNode, reactNode, options?)
- Referências
- Utilização
- Hidratando HTML renderizado pelo servidor
- Hidratando um documento inteiro
- Suprimindo erros inevitáveis de incompatibilidade de hidratação
- Tratando diferenças de conteúdo entre cliente e servidor
- Atualizando um componente raiz hidratado
- Mostrando diálogo para erros não interceptados
- Mostrando erros de Error Boundary
- Mostrando um diálogo para erros recuperáveis de diferença de hidratação
- Solução de problemas
Referências
hydrateRoot(domNode, reactNode, options?)
Use hydrateRoot
para “conectar” o React ao HTML existente que já foi renderizado pelo React do lado do servidor.
import { hydrateRoot } from 'react-dom/client';
const domNode = document.getElementById('root');
const root = hydrateRoot(domNode, reactNode);
React irá anexar o HTML existente dentro do domNode
, e assumir a gestão do DOM dentro dele. Um aplicativo completamente construído com React comumente só terá uma única chamada do hydrateRoot
para seu componente raiz.
Parâmetros
-
domNode
: Um elemento DOM que foi renderizado como elemento raiz no servidor. -
reactNode
: O “nó do React” usado para renderizar o HTML existente. Frequentemente será uma parte do JSX como<App />
que foi renderizado com um métodoReactDOM Server
comorenderToPipeableStream(<App />)
. -
opcional
options
: Um objeto com opções para a raiz do React.- Canary only opcional
onCaughtError
: Callback disparado quando o React intercepta um ero no Error Boundary. Vem com oerror
interceptado pelo Error Boundary, e um objetoerrorInfo
contendo ocomponentStack
. - Canary only opcional
onUncaughtError
: Callback disparado quando um erro é lançado e não interceptado por um Error Boundary. Vem com oerror
que foi lançado e um objetoerrorInfo
contendo ocomponentStack
. - opcional
onRecoverableError
: Callback disparado quando o React se recupera automaticamente de erros. Vem com oerror
que o React lançou, e um objetoerrorInfo
contendo ocomponentStack
. Alguns erros recuperáveis podem incluir a causa original do erro comoerror.cause
. - opcional
identifierPrefix
: Um prefixo de texto que o React usa para IDs gerados poruseId
. Útil para evitar conflitos quando múltiplas raizes são usadas na mesma página. Precisa ser o mesmo prefixo usado no servidor.
- Canary only opcional
Retornos
hydrateRoot
retorna um objeto com dois métodos: render
and unmount
.
Ressalvas
hydrateRoot()
espera que o conteúdo renderizado seja idêntico ao conteúdo renderizado pelo servidor. Você deve tratar diferenças como erros e corrigí-las.- No modo desenvolvedor, o React avisa sobre as diferenças na hidratação. Não há garantias de que as diferenças de atributos serão corrigidas em caso de incompatibilidades. Isso é importante por questões de performance porque na maioria dos aplicativos, diferenças são raras, e, portanto, validar todas as marcações seria proibitivamente caro.
- Você provavelmente terá apenas uma chamada
hydrateRoot
no seu aplicativo. Se você tiver um framework, ele pode fazer essa chamada para você. - Se a sua aplicação é redenrizada pelo cliente sem ter HTML renderizado ainda, usar
hydrateRoot()
não é suportado. UsecreateRoot()
alternativamente.
root.render(reactNode)
Chame root.render
para atualizar um componente React dentro de uma raiz hidratada do React em um elemento do DOM do navegador.
root.render(<App />);
React atualizará <App />
no root
hidratado.
Parâmetros
reactNode
: Um “nó React” que você quer atualizar. Será frequentemente uma parte do JSX como<App />
, mas vocẽ pode passar também um elemento React construído comcreateElement()
, uma string, um número,null
, orundefined
.
Retornos
root.render
retorna undefined
.
Ressalvas
- Se você chamar
root.render
antes do final da hidratação da raiz, o React irá limpar todo o conteúdo HTML existente renderizado no servidor e substituirá por todo conteúdo da raiz renderizada no cliente.
root.unmount()
Chame root.unmount
para desmontar uma árvore renderizada dentro da raiz do React.
root.unmount();
Um aplicativo completamente construído com React usualmente não precisará de nenhuma chamada para root.unmount
.
Isso é mais útil se o nó DOM da raiz do React (ou qualquer dos seus ascendentes) pode ser removido do DOM por outro código. Por examplo, imagine um painel de abas do jQuery que remove abas inativas do DOM. Se a aba for removida, tudo dentro dela (incluindo raízes React internas) seria removido do DOM também. Você precisa dizer para o React “parar” de gerenciar os conteúdos das raízes removidas chamando root.unmount
. Senão, os componentes dentro da raiz removida não limpará nem liberará os recursos como assinaturas.
Chamar root.unmount
desmontará todos os componente da raiz e “desconectará” o React do nó raiz do DOM, incluindo quaisquer manipuladores de evento ou state na árvore.
Parâmetros
root.unmount
não aceita nenhum parâmetro.
Retornos
root.unmount
retorna undefined
.
Ressalvas
-
Chamar
root.unmount
desmontará todos os componentes na árvore e “desconectará” o React do nó raiz do DOM. -
Depois de chamar
root.unmount
você não pode chamarroot.render
novamente para a raiz. Tentativas de chamarroot.render
com uma raiz desmontada lançará um “Cannot update an unmounted root” erro.
Utilização
Hidratando HTML renderizado pelo servidor
Se a sua aplicação HTML foi renderizada por react-dom/server
, você precisa hidratar ela no cliente.
import { hydrateRoot } from 'react-dom/client';
hydrateRoot(document.getElementById('root'), <App />);
Isso hidratará o HTML do servidor dentro do nó DOM do navegador com o componente React para a sua aplicação. Usualmente, você fará isso uma vez ao iniciar. Se você usa um framework, ele poderá fazer isso para você por trás das cenas.
Para hidratar sua aplicação, React “conectará” a lógica dos seus componentes ao HTML gerado no início pelo servidor. A hidratação transforma o snapshot inicial do HTML do servidor em uma aplicação completa e interativa rodando no navegador.
import './styles.css'; import { hydrateRoot } from 'react-dom/client'; import App from './App.js'; hydrateRoot( document.getElementById('root'), <App /> );
Você não precisará chamar hydrateRoot
novamente ou chamar em mais lugares. Desse ponto em diante, o React gerenciará o DOM de sua aplicação. Para atualizar a UI, seu componente irá usar state agora.
Hidratando um documento inteiro
Aplicações totalmente construídas com React podem renderizar o documento inteiro como JSX, incluindo o <html>
tag:
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>
);
}
Para hidratar o documento inteiro, passe o document
global como primeiro argumento para hydrateRoot
:
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(document, <App />);
Suprimindo erros inevitáveis de incompatibilidade de hidratação
Se um simples atributo do elemento ou conteúdo de texto inevitavelmente conter diferenças entre o servidor e o cliente (por examplo, um timestamp), você poderá silenciar o aviso de diferença de hidratação.
Para silenciar avisos de hidratação em um elemento, adicione suppressHydrationWarning={true}
:
export default function App() { return ( <h1 suppressHydrationWarning={true}> Current Date: {new Date().toLocaleDateString()} </h1> ); }
Somente funciona em um nível de profundidade, e é para ser usado como uma saída de emergência. Não abuse desse recurso. A menos que seja conteúdo de texto, o React ainda não tentará corrigi-lo, portanto pode permanecer inconsistente até atualizações futuras.
Tratando diferenças de conteúdo entre cliente e servidor
Se você intecionalmente precisa renderizar algo diferente no servidor e no cliente, você pode fazer uma renderização de dois passos. Componentes que renderizam algo diferente no cliente pode ler um state variable como isClient
, o qual você pode definir como true
em um Effect:
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> ); }
Dessa forma a renderização inicial passará a renderizar o mesmo conteúdo do servidor, evitando diferenças, mas um passo adicional acontecerá de forma síncrona logo após a hidratação.
Atualizando um componente raiz hidratado
Após a finalização da hidratação da raiz, você pode chamar root.render
para atualizar o componente raiz do React. Diferente de createRoot
, você não precisa frequentemente fazer isso porque o conteúdo inicial já renderizou como HTML.
Se você chamar root.render
em algum ponto após a hidratação, e a estrutura do componente árvore coincidir com o que foi previamente renderizado, o React preservará o state. Note como você pode escrever no campo de texto, o que significa que a atualização de repetidos render
chamados cada segundo nesse exemplo não são destrutivos:
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);
É incomum chamar root.render
para uma raiz hidratada. Ao invés disso, usualmente, você atualizará o state dentro de um dos componentes.
Mostrando diálogo para erros não interceptados
Por padrão, o React imprimirá no console todos os log’s de erros não interceptados. Para implementar seu prórpio relatório de erros, você pode definir o método opcional onUncaughtError
da raiz:
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 />);
O método onUncaughtError é uma função que é chamada com dois argumentos:
- O error que é lançado.
- Um objeto errorInfo que contém o componentStack do erro.
Você pode usar o método onUncaughtError
da raiz para exibir diálogos de erros:
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 }); } } });
Mostrando erros de Error Boundary
Por padrão, React impriirá todos os log’s de erros interceptados por um Error Boundary no console.error
. Para mudar esse comportmento, você pode definir o método opcional onCaughtError
da raiz para erros interceptados por 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 />);
O método onCaughtError é uma função que possui dois argumentos:
- O error que foi interceptado pelo boundary.
- Um objeto errorInfo que contém o componentStack do erro.
Você pode usar o método onCaughtError
da raiz para mostrar diálogos de erro ou filtrar erros conhecidos do log:
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 }); } } });
Mostrando um diálogo para erros recuperáveis de diferença de hidratação
Quando o React encontra uma diferença de hidratação, ele automaticamente tentará recuperar renderizando no cliente. Por padrão, o React imprimirá o log de erros de diferença de hidratação no console.error
. Para mudar esse comportamento, você pode definir o método opcional onRecoverableError
da raiz:
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
);
}
}
);
O método onRecoverableError é uma função com dois argumentos:
- O error lançado pelo React. Alguns erros podem incluir a causa original como error.cause.
- Um objeto errorInfo que contém o componentStack do erro.
Você pode usar o método onRecoverableError
da raiz para mostrar diálogos de erro para diferenças de hidratação:
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 }); } });
Solução de problemas
Estou recebendo esse erro: “You passed a second argument to root.render”
Um erro comum é passar as opções de hydrateRoot
para root.render(...)
:
Para correção, passe as opções da raiz para hydrateRoot(...)
, e não para root.render(...)
:
// 🚩 Wrong: root.render only takes one argument.
root.render(App, {onUncaughtError});
// ✅ Correct: pass options to createRoot.
const root = hydrateRoot(container, <App />, {onUncaughtError});