hydrateRoot
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
- Penggunaan
- Meng-hydrate server yang di-render di HTML
- Meng-hydrate seluruh dokumen
- Menekan kesalahan ketidakcocokan hydration yang tidak dapat dihindari
- Menangani konten klien dan server yang berbeda
- Memperbarui hydrated root component
- Menunjukkan dialog untuk error yang tidak ditangkap
- Menampilkan error dari Error Boundary
- Menunjukkan dialog untuk error ketidakcocokan hydration yang dapat dipulihkan
- Troubleshooting
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 methodReactDOM Server
sepertirenderToPipeableStream(<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 theerror
caught by the Error Boundary, and anerrorInfo
object containing thecomponentStack
. - Canary only optional
onUncaughtError
: Callback called when an error is thrown and not caught by an Error Boundary. Called with theerror
that was thrown and anerrorInfo
object containing thecomponentStack
. - opsional
onRecoverableError
: Callback yang dipanggil saat React berhasil pulih secara otomatis dari kesalahan. Dipanggil denganerror
yang dikembalikan React, dan obyekerrorInfo
berisicomponentStack
. Beberapa kesalahan yang dapat dipulihkan mungkin akan berisi kesalahan aslinya sebagaierror.cause
. - opsional
identifierPrefix
: Awalan string yang digunakan React untuk ID yang dihasilkan olehuseId
. Berguna untuk menghindari konflik ketika menggunakan beberapa akar pada halaman yang sama. Harus awalan yang sama dengan yang digunakan pada server.
- Canary only optional
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 gunakancreateRoot()
.
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 dengancreateElement()
, sebuah string, sebuah angka,null
, atauundefined
.
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 memanggilroot.render
lagi pada akar. Mencoba memanggilroot.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.
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.
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
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:
- error yang dilempar oleh kode.
- 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
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:
- error yang ditangkap oleh boundary.
- 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:
- error yang dilempar oleh React. Beberapa error mungkin menyediakan penyebab awal sebagai error.cause.
- 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(...)
:
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});