Halaman hasil server-side rendering muncul dengan cepat. Konten langsung ada di layar begitu HTML tiba. Tapi coba klik tombol di detik pertama itu, tidak akan terjadi apa-apa. Markup-nya sudah ada, tapi JavaScript yang seharusnya merespons klik itu belum terpasang. Hydration adalah langkah yang menutup jeda itu.
Apa yang Sebenarnya Dilakukan Hydration
Membangun halaman dari nol dan meng-hydrate halaman yang sudah ada terlihat mirip di kode, tapi keduanya bukan operasi yang sama:
// Client-side rendering: bangun DOM dari nol
createRoot(document.getElementById('root')).render(<App />);
// Hydration: menempel ke DOM yang sudah ada
hydrateRoot(document.getElementById('root'), <App />);
createRoot tidak peduli apa isi #root. Ia buang semuanya dan bangun dari awal. hydrateRoot melakukan kebalikannya: ia menganggap HTML di dalam #root sudah benar, menelusurinya node demi node, dan memakai ulang setiap elemen yang ditemukan alih-alih membuatnya lagi. Yang ditambahkan cuma bagian yang tidak bisa diungkapkan HTML sendiri: event listener, state komponen, ref.
Cocokkan, Baru Pasang
Langkah demi langkah, begini cara kerja hydration:
- HTML hasil server-side rendering tergambar. Pengguna langsung melihat konten sungguhan.
- Bundle JS untuk halaman itu dimuat, paralel atau tepat setelahnya.
hydrateRootmenelusuri DOM yang sudah ada, membandingkannya dengan apa yang seharusnya di-render framework sendiri: tag yang sama, urutan yang sama, atribut yang sama.- Di mana keduanya cocok, tidak ada yang dibangun ulang. Framework cuma memasang listener dan menyambungkan node itu ke pohon komponennya.
- Halaman jadi interaktif, tanpa satu pun elemen yang sempat berkedip hilang lalu muncul lagi.
Ketika Kecocokannya Gagal
Langkah 3 adalah titik di mana semuanya bisa berantakan. Kalau DOM yang sebenarnya ada di browser tidak cocok dengan apa yang diharapkan framework, itu namanya hydration mismatch, dan satu-satunya jalan keluar framework adalah membuang bagian yang tidak cocok itu dan membangunnya ulang di client, persis seperti yang akan dilakukan CSR biasa.
Beberapa cara mismatch ini muncul di kode sungguhan:
// server merender satu waktu, client merender waktu yang sedikit berbeda
<span>{new Date().toLocaleTimeString()}</span>
- Waktu dan locale: potongan kode di atas merender jam berapa pun saat itu di server, lalu jam yang sedikit berbeda di client. Dua string berbeda, komponen yang sama.
- ID acak atau hasil generate:
Math.random()atau UUID baru menghasilkan nilai berbeda di setiap render, termasuk di server. - Pengecekan yang hanya berlaku di
window: kode yang berperilaku beda tergantung ada tidaknyawindowakan merender satu cara di server (tidak adawindow) dan cara lain di browser. - Ekstensi browser: Grammarly dan tool sejenis menyuntikkan atribut ke DOM sebelum hydration sempat jalan, jadi “DOM yang sudah ada” yang diperiksa hydration sebenarnya bukan persis apa yang dikirim server.
Perbaikan untuk kasus timestamp biasanya bukan melawannya: render placeholder di server, dan isi nilai sungguhannya cuma setelah client mengambil alih.
const [time, setTime] = useState(null);
useEffect(() => setTime(new Date().toLocaleTimeString()), []);
return <span>{time ?? '--:--:--'}</span>;
Sekarang server dan client sepakat di render pertama (null), dan nilai sungguhannya baru muncul setelah hydration selesai, yang memang dari awal sudah pasti akan berubah di titik itu juga.
Biaya yang Tidak Terlihat Siapa Pun
Hydration tidak melewati pekerjaan yang dilakukan CSR, ia cuma memindahkannya. JS yang sama tetap harus diunduh, di-parsing, dan dijalankan, membangun pohon komponen yang persis sama seperti kalau dibangun dari nol, cuma untuk memastikan ia bisa memakai ulang apa yang sudah ada alih-alih membuatnya lagi. Halaman berat dengan puluhan komponen interaktif bisa terlihat sudah selesai total, padahal masih beberapa ratus milidetik lagi sebelum benar-benar merespons klik.
Itulah bagian anehnya SSR dalam skala besar: kontennya sungguhan, dan halamannya terlihat siap jauh sebelum benar-benar siap.
Kenapa Ini Penting
Hydration adalah jahitan di antara dua model rendering yang sudah dibahas sebelumnya. SSR melewati jeda halaman kosong ala CSR dengan mengirim HTML sungguhan lebih dulu. CSR membangun dan memasang interaktivitas sekaligus dalam satu proses, dan tidak ada yang ditampilkan sampai keduanya selesai. Hydration adalah yang dibayar SSR belakangan supaya tetap dapat interaktivitas ala CSR, tanpa harus melepas keunggulan first paint yang cepat itu. Biaya JavaScript-nya tetap sama seperti CSR, cuma dipindah ke setelah konten sudah ada di layar, bukan sebelumnya.
Terima Kasih Sudah Membaca✌️