Lokasi ngalangkungan proxy:   [ UP ]  
[Ngawartoskeun bug]   [Panyetelan cookie]                

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.

Veja mais exemplos abaixo.

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 do ReactDOM Server, como renderToPipeableStream(<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 o error capturado pelo Error Boundary e um objeto errorInfo contendo o componentStack.
    • opcional onUncaughtError: Callback chamado quando um erro é lançado e não é capturado por um Error Boundary. Chamado com o error que foi lançado e um objeto errorInfo contendo o componentStack.
    • opcional onRecoverableError: Callback chamado quando o React se recupera automaticamente de erros. Chamado com o error que o React lança e um objeto errorInfo contendo o componentStack. Alguns erros recuperáveis podem incluir a causa original do erro como error.cause.
    • opcional identifierPrefix: Um prefixo de string que o React usa para IDs gerados por useId. Útil para evitar conflitos ao usar várias raízes na mesma página. Deve ser o mesmo prefixo usado no servidor.

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 hydrateRoot em 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. Use createRoot() 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.

Veja mais exemplos abaixo.

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 com createElement(), uma string, um número, null ou undefined.

Retorna

root.render retorna undefined.

Ressalvas

  • Se você chamar root.render antes 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.unmount desmontará todos os componentes na árvore e “desanexará” o React do nó DOM raiz.

  • Depois de chamar root.unmount, você não poderá mais chamar root.render na raiz. Tentar chamar root.render em 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.

Pitfall

A árvore React que você passa para hydrateRoot precisa produzir a mesma saída que produziu no servidor.

Isso é importante para a experiência do usuário. O usuário passará algum tempo olhando para o HTML gerado pelo servidor antes que seu código JavaScript seja carregado. A renderização do servidor cria uma ilusão de que o aplicativo carrega mais rápido mostrando o snapshot HTML de sua saída. Mostrar repentinamente conteúdo diferente quebra essa ilusão. É por isso que a saída da renderização do servidor deve corresponder à saída da renderização inicial no cliente.

As causas mais comuns que levam a erros de hidratação incluem:

  • Espaços em branco extras (como novas linhas) em torno do HTML gerado pelo React dentro do nó raiz.
  • Usando verificações como typeof window !== 'undefined' em sua lógica de renderização.
  • Usando APIs exclusivas do navegador como window.matchMedia em sua lógica de renderização.
  • Renderizando dados diferentes no servidor e no cliente.

O React se recupera de alguns erros de hidratação, mas você deve corrigi-los como outros bugs. Na melhor das hipóteses, eles levarão a uma lentidão; na pior das hipóteses, os manipuladores de eventos podem ser anexados aos elementos errados.


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.

Pitfall

Essa abordagem torna a hidratação mais lenta porque seus componentes precisam renderizar duas vezes. Tenha cuidado com a experiência do usuário em conexões lentas. O código JavaScript pode carregar significativamente depois da renderização HTML inicial, então renderizar uma interface diferente imediatamente após a hidratação também pode parecer chocante para o usuário.


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:

  1. O erro que foi lançado.
  2. 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(...):

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

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