hydrateRoot memungkinkan Anda menampilkan komponen React di dalam DOM node peramban yang konten HTML-nya sebelumnya dibuat oleh react-dom/server.

const root = hydrateRoot(domNode, reactNode, options?)

Referensi

hydrateRoot(domNode, reactNode, options?)

Panggil fungsi hydrateRoot untuk “menambahkan” React ke dalam HTML yang sudah ada yang sebelumnya di-render oleh React di dalam environment server.

import { hydrateRoot } from 'react-dom/client';

const domNode = document.getElementById('root');
const root = hydrateRoot(domNode, reactNode);

React akan ditambahkan ke dalam HTML yang ada di dalam domNode, dan mengambil alih pengelolaan DOM didalamnya. Sebuah aplikasi yang sepenuhnya dibangun dengan React biasanya hanya akan memiliki satu pemanggilan hydrateRoot dengan komponen root-nya.

Lihat contoh-contoh lainnya di bawah ini.

Parameter

  • domNode: Elemen DOM yang di-render sebagai elemen akar di server.

  • reactNode: “React node” yang digunakan untuk me-render HTML yang ada. Biasanya berupa bagian dari JSX seperti <App /> yang dengan method ReactDOM Server seperti renderToPipeableStream(<App />).

  • opsional options: Objek dengan opsi untuk akar React.

    • Canary only optional onCaughtError: Callback called when React catches an error in an Error Boundary. Called with the error caught by the Error Boundary, and an errorInfo object containing the componentStack.
    • Canary only optional onUncaughtError: Callback called when an error is thrown and not caught by an Error Boundary. Called with the error that was thrown and an errorInfo object containing the componentStack.
    • opsional onRecoverableError: Callback yang dipanggil saat React berhasil pulih secara otomatis dari kesalahan. Dipanggil dengan error yang dikembalikan React, dan obyek errorInfo berisi componentStack. Beberapa kesalahan yang dapat dipulihkan mungkin akan berisi kesalahan aslinya sebagai error.cause.
    • opsional identifierPrefix: Awalan string yang digunakan React untuk ID yang dihasilkan oleh useId. Berguna untuk menghindari konflik ketika menggunakan beberapa akar pada halaman yang sama. Harus awalan yang sama dengan yang digunakan pada server.

Kembalian

hydrateRoot mengembalikan objek dengan dua method: render dan unmount.

Catatan penting

  • hydrateRoot() mengharapkan konten yang di-render identik dengan konten yang di-render server. Anda harus memperlakukan ketidakcocokan sebagai bug dan memperbaikinya.
  • Dalam mode pengembangan, React memperingatkan tentang ketidakcocokan selama hydration. Tidak ada jaminan bahwa perbedaan atribut akan diperbaiki jika terjadi ketidakcocokan. Hal ini penting untuk alasan performa karena pada sebagian besar aplikasi, ketidakcocokan jarang terjadi, sehingga memvalidasi semua markup akan sangat mahal.
  • Anda mungkin hanya akan memiliki satu panggilan hydrateRoot dalam aplikasi Anda. Jika Anda menggunakan framework, framework tersebut mungkin akan melakukan pemanggilan ini untuk Anda.
  • Jika aplikasi Anda di-render oleh klien tanpa HTML yang telah di-render, penggunaan hydrateRoot() tidak disarankan. Sebaiknya gunakan createRoot().

root.render(reactNode)

Panggil root.render untuk memperbarui komponen React di dalam hydrated React root untuk elemen DOM peramban.

root.render(<App />);

React akan memperbarui <App /> di dalam hydrated root.

Lihat contoh-contoh lainnya di bawah ini.

Parameter

  • reactNode: Sebuah “React node” yang ingin Anda perbarui. Biasanya berupa bagian dari JSX seperti <App />, tetapi Anda juga dapat mengoper elemen React yang dibangun dengan createElement(), sebuah string, sebuah angka, null, atau undefined.

Kembalian

root.render mengembalikan undefined.

Catatan penting

  • Jika Anda memanggil root.render sebelum akar selesai melakukan hydrating, React akan menghapus konten HTML yang di-render oleh server dan mengalihkan seluruh akar ke render klien.

root.unmount()

Panggil root.unmount untuk menghancurkan pohon yang di-render di dalam akar React.

root.unmount();

Aplikasi yang sepenuhnya dibangun dengan React biasanya tidak akan memiliki panggilan ke root.unmount.

Hal ini sangat berguna jika akar React DOM node (atau salah satu dari induknya) mungkin akan dihapus dari DOM oleh kode lain. Sebagai contoh, bayangkan sebuah panel tab jQuery menghapus tab yang tidak aktif dari DOM. Jika sebuah tab dihapus, semua yang ada di dalamnya (termasuk akar React di dalamnya) akan dihapus dari DOM juga. Anda perlu memberi tahu React untuk “berhenti” mengelola akar konten yang telah dihapus dengan memanggil root.unmount. Jika tidak, komponen-komponen di dalam akar yang dihapus tidak akan dibersihkan dan membebaskan sumber daya seperti langganan.

Memanggil root.unmount akan melepas semua komponen di root dan “melepaskan” React dari akar DOM node, termasuk menghapus semua event handler atau state di dalam pohon.

Parameter

root.unmount tidak menerima parameter apa pun.

Kembalian

root.unmount mengembalikan undefined.

Catatan penting

  • Memanggil root.unmount akan melepas semua komponen di dalam pohon dan “melepaskan” React dari akar DOM node.

  • Setelah Anda memanggil root.unmount Anda tidak dapat memanggil root.render lagi pada akar. Mencoba memanggil root.render pada akar yang tidak terpasang akan menimbulkan kesalahan berupa “Cannot update an unmounted root”.


Penggunaan

Meng-hydrate server yang di-render di HTML

Jika HTML aplikasi Anda dibuat oleh react-dom/server, Anda perlu melakukan hydrate kepada klien.

import { hydrateRoot } from 'react-dom/client';

hydrateRoot(document.getElementById('root'), <App />);

Ini akan meng-hydrate server HTML di dalam peramban DOM node dengan komponen React untuk aplikasi Anda. Biasanya, Anda akan melakukannya sekali pada saat dijalankan. Jika Anda menggunakan framework, framework tersebut mungkin akan melakukan hal ini di belakang layar untuk Anda.

Untuk meng-hydrate aplikasi Anda, React akan “menambahkan” logika komponen Anda ke HTML yang dihasilkan dari server. Hydration mengubah gambaran HTML awal dari server menjadi aplikasi yang sepenuhnya interaktif yang berjalan di peramban.

import './styles.css';
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';

hydrateRoot(
  document.getElementById('root'),
  <App />
);

Anda seharusnya tidak perlu memanggil hydrateRoot lagi atau memanggilnya di banyak tempat. Mulai saat ini, React akan mengelola DOM aplikasi Anda. Untuk memperbarui UI, komponen Anda akan menggunakan state sebagai gantinya.

Sandungan

Pohon React yang Anda berikan ke hydrateRoot harus menghasilkan keluaran yang sama dengan yang dihasilkan di server.

Hal ini penting untuk pengalaman pengguna. Pengguna akan menghabiskan waktu untuk melihat HTML yang dihasilkan server sebelum kode JavaScript Anda dimuat. Perenderan server menciptakan ilusi bahwa aplikasi dimuat lebih cepat dengan menampilkan cuplikan HTML dari keluarannya. Menampilkan konten yang berbeda secara tiba-tiba akan mematahkan ilusi tersebut. Inilah sebabnya mengapa output render server harus sesuai dengan output render awal pada client.

Penyebab paling umum yang menyebabkan kesalahan hydration antara lain:

  • Spasi ekstra (seperti baris baru) di sekitar HTML yang dihasilkan React di dalam akar node.
  • Menggunakan pemeriksaan seperti typeof window !== 'undefined' dalam logika rendering Anda.
  • Menggunakan API khusus peramban seperti window.matchMedia dalam logika rendering Anda.
  • Me-render data yang berbeda pada server dan klien.

React pulih dari beberapa kesalahan hydration, tetapi Anda harus memperbaikinya seperti bug lainnya. Dalam kasus terbaik, mereka akan menyebabkan perlambatan; dalam kasus terburuk, event handler dapat melekat pada elemen yang salah.


Meng-hydrate seluruh dokumen

Aplikasi yang sepenuhnya dibangun dengan React dapat me-render seluruh dokumen sebagai JSX, termasuk 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>
);
}

Untuk meng-hydrate seluruh dokumen, berikan document bersifat global sebagai argumen pertama ke hydrateRoot:

import { hydrateRoot } from 'react-dom/client';
import App from './App.js';

hydrateRoot(document, <App />);

Menekan kesalahan ketidakcocokan hydration yang tidak dapat dihindari

Jika atribut atau konten teks dari satu elemen tidak dapat dihindari berbeda antara server dan klien (misalnya, timestamp), Anda dapat membungkam peringatan ketidakcocokan hydration.

Untuk membungkam peringatan hydration pada sebuah elemen, tambahkan suppressHydrationWarning={true}:

export default function App() {
  return (
    <h1 suppressHydrationWarning={true}>
      Tanggal Sekarang: {new Date().toLocaleDateString()}
    </h1>
  );
}

Ini hanya berfungsi satu tingkat, dan dimaksudkan sebagai jalan keluar. Jangan terlalu sering menggunakannya. Kecuali jika itu adalah konten teks, React masih belum mencoba untuk memperbaikinya, sehingga mungkin tetap tidak konsisten hingga pembaruan di masa mendatang.


Menangani konten klien dan server yang berbeda

Jika Anda secara sengaja ingin me-render sesuatu yang berbeda di server dan klien, Anda dapat melakukan rendering dua kali. Komponen yang me-render sesuatu yang berbeda di klien dapat membaca variabel state seperti isClient, yang dapat Anda setel menjadi true di dalam 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>
  );
}

Dengan cara ini proses render awal akan me-render konten yang sama seperti server, sehingga menghindari ketidakcocokan, tetapi proses tambahan akan terjadi secara serempak setelah hydration.

Sandungan

Pendekatan ini membuat hydration menjadi lebih lambat karena komponen Anda harus di-render dua kali. Perhatikan pengalaman pengguna pada koneksi yang lambat. Kode JavaScript dapat dimuat secara signifikan lebih lambat daripada render HTML awal, sehingga me-render UI yang berbeda segera setelah hydration juga dapat terasa mengagetkan pengguna.


Memperbarui hydrated root component

Setelah root telah selesai melakukan proses hydrating, Anda dapat memanggil root.render untuk memperbarui komponen root React. Tidak seperti pada createRoot, Anda biasanya tidak perlu melakukan hal ini karena konten awal telah di-render sebagai HTML.

Jika Anda memanggil root.render pada suatu saat setelah hydration, dan struktur pohon komponen sesuai dengan apa yang sebelumnya di-render, React akan mempertahankan state. Perhatikan bagaimana Anda dapat mengetikkan input, dimana pembaruan dari pemanggilan render diulang-ulang setiap detik pada contoh ini tidak bersifat destruktif:

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

Tidak lazim untuk memanggil root.render pada hydrated root. Biasanya, Anda akan memperbarui state di dalam salah satu komponen sebagai gantinya.

Menunjukkan dialog untuk error yang tidak ditangkap

Canary

onUncaughtError hanya tersedia di rilis Canary React terbaru.

Secara bawaan, React akan me-log semua error yang tidak ditangkap di konsol. Untuk mengimplementasi pelaporan error Anda sendiri, Anda dapat menyediakan pengaturan opsional onUncaughtError:

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

Pengaturan onUncaughtError adalah fungsi yang dipanggil dengan dua argumen:

  1. error yang dilempar oleh kode.
  2. Obyek errorInfo yang berisi componentStack dari error tersebut.

Anda dapat menggunakan opsi root onUncaughtError untuk menunjukkan dialog error:

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

Menampilkan error dari Error Boundary

Canary

onCaughtError hanya tersedia di rilis Canary React terbaru.

Secara bawaan, React akan me-log semua error yang ditangkap di Error Boundary ke console.error. Untuk mengesampingkan perilaku ini, Anda dapat memberikan opsi root onCaughtError opsional untuk kesalahan yang ditangkap oleh 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 />);

Pengaturan onUncaughtError adalah fungsi yang dipanggil dengan dua argumen:

  1. error yang ditangkap oleh boundary.
  2. Obyek errorInfo yang berisi componentStack dari error tersebut.

Anda dapat menggunakan opsi root onUncaughtError untuk menunjukkan dialog error atau memfilter error yang diketahui dari logging:

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

Menunjukkan dialog untuk error ketidakcocokan hydration yang dapat dipulihkan

Ketika React mengalami ketidakcocokan hydration, React akan secara otomatis mencoba memulihkannya dengan melakukan rendering pada klien. Secara default, React akan mencatat kesalahan ketidakcocokan hydration ke console.error. Untuk mengesampingkan perilaku ini, Anda dapat memberikan pengaturan root onRecoverableError opsional:

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

Pengaturan onUncaughtError adalah fungsi yang dipanggil dengan dua argumen:

  1. error yang dilempar oleh React. Beberapa error mungkin menyediakan penyebab awal sebagai error.cause.
  2. Obyek errorInfo yang berisi componentStack dari error tersebut.

Anda dapat menggunakan opsi root onUncaughtError untuk menunjukkan dialog error untuk ketidakcocokan hydration:

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

Troubleshooting

Saya mendapatkan error: “You passed a second argument to root.render”

Kesalahan umum adalah mengoper opsi untuk hydrateRoot ke root.render(...):

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

Untuk memperbaikinya, oper opsi akar ke hydrateRoot(...), bukan root.render(...):

// 🚩 Wrong: root.render only takes one argument.
root.render(App, {onUncaughtError});

// ✅ Correct: pass options to createRoot.
const root = hydrateRoot(container, <App />, {onUncaughtError});