hydrateRoot
hydrateRoot permite que você exiba componentes React dentro de um nó DOM do navegador cujo conteúdo HTML foi gerado anteriormente por react-dom/server.
const root = hydrateRoot(domNode, reactNode, options?)Referência
hydrateRoot(domNode, reactNode, options?)
Chame hydrateRoot para “anexar” o React a um HTML existente que já foi renderizado pelo React em um ambiente de servidor.
import { hydrateRoot } from 'react-dom/client';
const domNode = document.getElementById('root');
const root = hydrateRoot(domNode, reactNode);O React se anexará ao HTML que existe dentro do domNode e assumirá o gerenciamento do DOM dentro dele. Um aplicativo totalmente construído com React geralmente terá apenas uma chamada hydrateRoot com seu componente raiz.
Parâmetros
-
domNode: Um elemento DOM que foi renderizado como o elemento raiz no servidor. -
reactNode: O “nó React” usado para renderizar o HTML existente. Geralmente será um trecho de JSX como<App />, que foi renderizado com um método doReactDOM Server, comorenderToPipeableStream(<App />). -
opcional
options: Um objeto com opções para esta raiz React.- opcional
onCaughtError: Callback chamado quando o React captura um erro em um Error Boundary. Chamado com oerrorcapturado pelo Error Boundary e um objetoerrorInfocontendo ocomponentStack. - opcional
onUncaughtError: Callback chamado quando um erro é lançado e não é capturado por um Error Boundary. Chamado com oerrorque foi lançado e um objetoerrorInfocontendo ocomponentStack. - opcional
onRecoverableError: Callback chamado quando o React se recupera automaticamente de erros. Chamado com oerrorque o React lança e um objetoerrorInfocontendo ocomponentStack. Alguns erros recuperáveis podem incluir a causa original do erro comoerror.cause. - opcional
identifierPrefix: Um prefixo de string que o React usa para IDs gerados poruseId. Útil para evitar conflitos ao usar várias raízes na mesma página. Deve ser o mesmo prefixo usado no servidor.
- opcional
Retorna
hydrateRoot retorna um objeto com dois métodos: render e unmount.
Ressalvas
hydrateRoot()espera que o conteúdo renderizado seja idêntico ao conteúdo renderizado pelo servidor. Você deve tratar as incompatibilidades como bugs e corrigi-las.- No modo de desenvolvimento, o React avisa sobre incompatibilidades durante a hidratação. Não há garantias de que as diferenças de atributos serão corrigidas em caso de incompatibilidades. Isso é importante por razões de desempenho, pois na maioria dos aplicativos, as incompatibilidades são raras, e validar toda a marcação seria proibitivamente caro.
- Você provavelmente terá apenas uma chamada
hydrateRootem seu aplicativo. Se você usar um framework, ele pode fazer essa chamada para você. - Se o seu aplicativo for renderizado no cliente sem nenhum HTML já renderizado, usar
hydrateRoot()não é suportado. UsecreateRoot()em vez disso.
root.render(reactNode)
Chame root.render para atualizar um componente React dentro de uma raiz React hidratada para um elemento DOM do navegador.
root.render(<App />);O React atualizará <App /> na root hidratada.
Parâmetros
reactNode: Um “nó React” que você deseja atualizar. Geralmente será um trecho de JSX como<App />, mas você também pode passar um elemento React construído comcreateElement(), uma string, um número,nullouundefined.
Retorna
root.render retorna undefined.
Ressalvas
- Se você chamar
root.renderantes que a raiz termine de hidratar, o React limpará o conteúdo HTML existente renderizado pelo servidor e mudará toda a raiz para a renderização do cliente.
root.unmount()
Chame root.unmount para destruir uma árvore renderizada dentro de uma raiz React.
root.unmount();Um aplicativo totalmente construído com React geralmente não terá nenhuma chamada para root.unmount.
Isso é útil principalmente se o nó DOM da raiz React (ou qualquer um de seus ancestrais) puder ser removido do DOM por algum outro código. Por exemplo, imagine um painel de abas do jQuery que remove abas inativas do DOM. Se uma aba for removida, tudo dentro dela (incluindo as raízes React) também seria removido do DOM. Você precisa dizer ao React para “parar” de gerenciar o conteúdo da raiz removida chamando root.unmount. Caso contrário, os componentes dentro da raiz removida não farão a limpeza e liberarão recursos como assinaturas.
Chamar root.unmount desmontará todos os componentes na raiz e “desanexará” o React do nó DOM raiz, incluindo a remoção de quaisquer manipuladores de eventos ou estado na árvore.
Parâmetros
root.unmount não aceita nenhum parâmetro.
Retorna
root.unmount retorna undefined.
Ressalvas
-
Chamar
root.unmountdesmontará todos os componentes na árvore e “desanexará” o React do nó DOM raiz. -
Depois de chamar
root.unmount, você não poderá mais chamarroot.renderna raiz. Tentar chamarroot.renderem uma raiz desmontada lançará um erro “Cannot update an unmounted root”.
Uso
Hidratando HTML renderizado pelo servidor
Se o HTML do seu aplicativo foi gerado por react-dom/server, você precisa hidratá-lo 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 do seu aplicativo. Geralmente, você fará isso uma vez na inicialização. Se você usar um framework, ele pode fazer isso nos bastidores para você.
Para hidratar seu aplicativo, o React “anexará” a lógica dos seus componentes ao HTML inicial gerado pelo servidor. A hidratação transforma o snapshot HTML inicial do servidor em um aplicativo totalmente interativo que é executado no navegador.
import './styles.css'; import { hydrateRoot } from 'react-dom/client'; import App from './App.js'; hydrateRoot( document.getElementById('root'), <App /> );
Você não deve precisar chamar hydrateRoot novamente ou chamá-lo em mais lugares. A partir deste ponto, o React gerenciará o DOM do seu aplicativo. Para atualizar a interface do usuário, seus componentes usarão estado em vez disso.
Hidratando um documento inteiro
Aplicativos totalmente construídos com React podem renderizar o documento inteiro como JSX, incluindo a 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>
);
}Para hidratar o documento inteiro, passe o global document como o primeiro argumento para hydrateRoot:
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(document, <App />);Suprimindo erros de incompatibilidade de hidratação inevitáveis
Se o atributo ou conteúdo de texto de um único elemento for inegavelmente diferente entre o servidor e o cliente (por exemplo, um timestamp), você pode silenciar o aviso de incompatibilidade 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> ); }
Isso funciona apenas em um nível de profundidade e destina-se a ser uma saída de emergência. Não o use em excesso. O React não tentará corrigir o conteúdo de texto incompatível.
Lidando com conteúdo diferente no cliente e no servidor
Se você precisar intencionalmente renderizar algo diferente no servidor e no cliente, pode fazer uma renderização em duas passagens. Componentes que renderizam algo diferente no cliente podem ler uma variável de estado como isClient, que 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 passagem de renderização inicial renderizará o mesmo conteúdo do servidor, evitando incompatibilidades, mas uma passagem adicional ocorrerá de forma síncrona logo após a hidratação.
Atualizando um componente raiz hidratado
Após a raiz terminar de hidratar, você pode chamar root.render para atualizar o componente raiz React. Ao contrário de createRoot, você normalmente não precisa fazer isso porque o conteúdo inicial já foi renderizado como HTML.
Se você chamar root.render em algum momento após a hidratação, e a estrutura da árvore de componentes corresponder ao que foi renderizado anteriormente, o React preservará o estado. Observe como você pode digitar no input, o que significa que as atualizações das chamadas repetidas de render a cada segundo neste exemplo não são destrutivas:
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 em uma raiz hidratada. Geralmente, você atualizará o estado dentro de um dos componentes em vez disso.
Registro de erros em produção
Por padrão, o React registrará todos os erros no console. Para implementar seu próprio relatório de erros, você pode fornecer as opções opcionais de raiz de manipulador de erros 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,
});
}
},
});A opção onCaughtError é uma função chamada com dois argumentos:
- O erro que foi lançado.
- Um objeto errorInfo que contém o componentStack do erro.
Junto com onUncaughtError e onRecoverableError, você pode implementar seu próprio sistema de relatório de erros:
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 />, { // Lembre-se de remover essas opções em desenvolvimento para aproveitar // os manipuladores padrão do React ou implementar sua própria sobreposição para desenvolvimento. // Os manipuladores são especificados incondicionalmente aqui apenas para fins de demonstração. onCaughtError: onCaughtErrorProd, onRecoverableError: onRecoverableErrorProd, onUncaughtError: onUncaughtErrorProd, });
Solução de problemas
Estou recebendo um erro: “You passed a second argument to root.render”
Um erro comum é passar as opções para hydrateRoot para root.render(...):
Para corrigir, passe as opções da raiz para hydrateRoot(...), não para root.render(...):
// 🚩 Errado: root.render aceita apenas um argumento.
root.render(App, {onUncaughtError});
// ✅ Correto: passe as opções para createRoot.
const root = hydrateRoot(container, <App />, {onUncaughtError});