Masalah dan Konteks yang Berlaku
Sebuah halaman produk Next.js App Router melakukan prerender HTML, kemudian memuat JavaScript di browser untuk membuat tombol favorit dan formulir kembali-tersedia (back-in-stock) menjadi interaktif. Pemantauan production melaporkan React error #418 pada sebagian kecil kunjungan pertama. Pengguna yang terdampak mungkin melihat kilatan (flash) pada waktu atau tema, label formulir sempat kehilangan kaitannya, atau tombol favorit dibuat ulang. Local development dan navigasi sisi klien setelahnya biasanya terlihat normal.
Sebuah tinjauan menemukan empat operasi berisiko di dalam render path Client Component yang sama: memformat waktu dengan zona waktu default browser, percabangan pada tema dari localStorage, membuat ID formulir dengan Math.random(), dan menghasilkan rich text yang dapat membuat nesting tidak valid. Sebuah CDN berada di depan production, dan beberapa pengguna memiliki ekstensi browser yang mengubah halaman. Jelaskan cara mengidentifikasi tahap yang membuat snapshot server berbeda dari render klien pertama, tanpa menonaktifkan SSR untuk seluruh halaman atau menyembunyikan peringatan secara luas.
Panduan wawancara frontend senior 2026 KORE1 secara langsung meminta kandidat untuk men-debug hydration mismatch khusus production yang tidak dapat direproduksi secara lokal. Bank soal React 2026 MockIF juga mencantumkan hidrasi sebagai pertanyaan arsitektur tingkat lanjut. Dokumentasi React dan Next.js menetapkan kontrak output yang identik dan mengidentifikasi waktu, nilai acak, API browser, nesting yang tidak valid, dan mutasi DOM eksternal sebagai penyebabnya. Oleh karena itu, pertanyaan ini memiliki representasi wawancara terkini yang dapat diverifikasi. Keterampilan intinya adalah rendering browser dan debugging React hydration, sehingga kategorinya adalah frontend. Pertanyaan yang ada tentang event loop, caching, performa, keys, dan stale closures tidak mencakup kontrak ini.
Apa yang Sedang Dievaluasi oleh Pewawancara
Pertama, dapatkah kandidat mendefinisikan hidrasi secara tepat? Pada pemuatan awal, pengguna melihat HTML yang telah di-prerender. Browser mem-parse-nya, dan React memasang logika komponen serta event handler ke DOM yang sudah ada. Client Component tetap dapat berpartisipasi dalam prerendering HTML awal; "use client" tidak berarti rendering hanya di browser pada pemuatan pertama. Kontrak ini membandingkan hasil server dengan render pertama klien, bukan dua render berikutnya yang arbitrer.
Kedua, dapatkah kandidat memisahkan empat kelas perbedaan menggunakan bukti? Input aplikasi mungkin berbeda, seperti snapshot data, waktu saat ini, atau nilai acak. Lingkungan eksekusi (execution environments) mungkin berbeda melalui window, localStorage, bahasa, atau zona waktu. Browser dapat memperbaiki HTML yang tidak valid menjadi DOM yang berbeda. Terakhir, CDN, ekstensi, atau skrip dapat memutasi node sebelum React dimulai. Hanya melihat component stack dapat melewatkan parsing atau mutasi eksternal yang terjadi sebelumnya.
Ketiga, dapatkah kandidat memetakan setiap penyebab ke perbaikan yang sesuai? Input yang stabil harus diserialisasi dan digunakan kembali sebagai satu snapshot. Lingkungan pengguna dapat diselesaikan di server dari cookie atau profil, atau diperbarui dalam Effect setelah hidrasi. ID DOM acak harus menggunakan useId. Nesting yang tidak valid harus diperbaiki. SSR harus dinonaktifkan hanya untuk komponen pihak ketiga kecil yang benar-benar tidak dapat di-prerender.
Terakhir, dapatkah kandidat membuktikan bahwa cacat tersebut telah hilang? Rencana yang kuat mencakup production build, cold initial load, JavaScript lambat, kombinasi lokal dan zona waktu, cache hit, browser bersih, dan browser yang terpengaruh ekstensi. Rencana ini memeriksa kesalahan, identitas DOM, state interaksi, dan kilatan visual. Konsol yang hening adalah satu hasil, bukan bukti lengkap.
Pertanyaan Klarifikasi Sebelum Menjawab
- Apakah error hanya terjadi pada pemuatan dokumen awal, atau juga pada navigasi klien? Hidrasi adalah pengambilalihan pertama React atas HTML yang ada. Cacat pada navigasi lanjutan menunjukkan masalah state, caching, atau async race.
- Apakah mismatch terjadi pada teks, atribut, struktur node, atau seluruh subtree? Simpan seluruh error, component stack, route, dan versi deployment alih-alih menebak dari nomor error production yang terpotong.
- Apakah server mengetahui lokal, zona waktu, tema, dan experiment bucket pengguna? Nilai yang tersedia melalui URL, cookie, atau profil harus ditentukan di server dan diteruskan ke klien. Nilai yang tidak diketahui membutuhkan placeholder stabil atau pembaruan pasca-hidrasi.
- Apakah render klien pertama menggunakan snapshot data bisnis yang persis sama dengan yang menghasilkan HTML? Meskipun browser telah mengambil data yang lebih baru sebelum hidrasi, tampilan awal harus dimulai dari snapshot yang diserialisasi dan di-refresh hanya setelah hidrasi.
- Apakah HTML melewati CDN, proxy terjemahan, injektor keamanan, atau pengoptimal? Tangkap respons origin dan edge untuk melihat apakah ada perantara yang mengubah spasi putih, atribut, tag, atau urutan skrip.
- Apakah error terbatas pada ekstensi, browser seluler, atau wilayah tertentu? Hal tersebut menentukan apakah perlu membandingkan isi respons jaringan dengan DOM aktual tepat sebelum React dimulai.
- Apakah subtree ini memerlukan prerendering? Konten yang berharga untuk SEO, first paint, atau keterbacaan tanpa JavaScript harus mempertahankan SSR. Widget leaf khusus browser dapat membenarkan
ssr: falselokal. - Perubahan visual apa yang dapat diterima? Two-pass rendering dapat mempertahankan kontrak hidrasi tetapi membuat perubahan yang terlihat pada koneksi lambat. Sepakati konten placeholder, stabilitas tata letak, dan aksesibilitas terlebih dahulu.
Kerangka Jawaban 30 Detik
"Hidrasi mensyaratkan HTML server dan render pertama klien menghasilkan struktur dan konten yang sama. Saya akan menangkap error, component stack, route, versi, lokal, dan zona waktu, kemudian menyelaraskan tiga bukti: HTML yang diterima melalui jaringan, DOM yang di-parse browser sebelum React mengambil alih, dan input ke render klien pertama. Jika HTML jaringan sudah berbeda, periksa snapshot data dan CDN. Jika berubah selama parsing, periksa nesting yang tidak valid, ekstensi, dan skrip awal. Jika berbeda saat React me-render, periksa waktu, keacakan, API browser, dan refresh data awal. Saya akan menggunakan kembali satu snapshot yang diserialisasi, menentukan locale dan timeZone, menggunakan useId, dan menurunkan state browser dari cookie atau setelah hidrasi dalam Effect. Saya akan mencadangkan ssr: false untuk leaf khusus browser dan suppressHydrationWarning untuk perbedaan teks satu tingkat yang tidak dapat dihindari. Kemudian saya akan menjalankan cold production load di seluruh matriks lingkungan dan memverifikasi tidak ada recoverable error, penggantian subtree, flash, atau bug interaksi."
Pembahasan Mendalam Langkah demi Langkah
Langkah 1: nyatakan invarian sebelum men-debug komponen.
Misalkan component tree server menghasilkan HTML dari snapshot input S. Browser mem-parse HTML menjadi DOM D, dan klien melakukan render pertamanya dengan input C. Hidrasi yang berhasil mensyaratkan D dan tree klien cocok untuk node, teks, dan atribut yang diandalkan React. Tujuannya bukan sekadar membuktikan bahwa kedua lingkungan memuat file sumber yang sama. Tujuannya adalah membuktikan bahwa S, parsing, dan C menghasilkan hasil yang sama.
React tidak menjamin bahwa setiap perbedaan atribut akan ditambal (patched). Beberapa mismatch dapat dipulihkan (recoverable) dan menyebabkan subtree dibuat ulang; dalam kasus terburuk, handler dapat terpasang ke elemen yang salah. Oleh karena itu, hydration mismatch bukanlah sekadar gangguan konsol yang tidak berbahaya.
Langkah 2: buat paket bukti yang merepresentasikan first load production.
Catat route, versi deployment, request ID, status cache, lokal, zona waktu, sumber tema, experiment bucket, User-Agent, dan full component stack tanpa mengumpulkan nilai sensitif. Gunakan production build dan pemuatan ulang penuh (full reload). Hot reload, perilaku khusus development, dan navigasi klien tidak mereproduksi cold start di production.
Untuk satu permintaan, simpan tiga artefak: response body yang dikembalikan oleh origin atau CDN, DOM yang di-parse dengan JavaScript dinonaktifkan, dan DOM tepat sebelum serta setelah error dengan JavaScript diaktifkan. Jika responsnya benar tetapi Elements tree sudah berbeda, periksa koreksi HTML parser, ekstensi, dan skrip pra-React terlebih dahulu. Jika DOM menyimpang hanya ketika React dimulai, bandingkan input first-render.
Langkah 3: hilangkan nondeterminisme dari render path.
Kode berikut memungkinkan server dan browser menggunakan lingkungan yang berbeda dan menghasilkan ID baru pada setiap render:
"use client"
export function StockNotice({ updatedAt }: { updatedAt: string }) {
const isBrowser = typeof window !== "undefined"
const theme = isBrowser ? localStorage.getItem("theme") ?? "light" : "light"
const inputId = `stock-${Math.random()}`
return (
<section data-theme={theme}>
<time dateTime={updatedAt}>{new Date(updatedAt).toLocaleString()}</time>
<label htmlFor={inputId}>Back-in-stock alert</label>
<input id={inputId} />
</section>
)
}Lebih baik selesaikan nilai yang stabil di server dan teruskan nilai persis tersebut sebagai input awal Client Component. Jika lokal, zona waktu, dan tema tersedia di URL, cookie, atau profil, bacalah di server. Pemformatan tanggal harus menerima locale dan timeZone yang eksplisit. ID DOM harus menggunakan useId, asalkan component tree server dan klien tetap identik:
"use client"
import { useId } from "react"
interface StockNoticeProps {
updatedAt: string
updatedLabel: string
initialTheme: "light" | "dark"
}
export function StockNotice({
updatedAt,
updatedLabel,
initialTheme,
}: StockNoticeProps) {
const inputId = useId()
return (
<section data-theme={initialTheme}>
<time dateTime={updatedAt}>{updatedLabel}</time>
<label htmlFor={inputId}>Back-in-stock alert</label>
<input id={inputId} />
</section>
)
}Jika server benar-benar tidak dapat mengetahui zona waktu browser, render label UTC atau placeholder tetap yang sama di kedua sisi, lalu ganti di useEffect setelah hidrasi. Hal ini menambah satu kali render, jadi sediakan ruang dan nilai perubahan visual pada koneksi lambat. Terapkan aturan yang sama untuk data bisnis: serialisasikan snapshot yang menghasilkan HTML, gunakan untuk render klien pertama, dan biarkan background refresh memperbarui tampilan hanya setelah hidrasi.
Langkah 4: periksa browser parsing dan mutasi eksternal.
Browser memperbaiki HTML yang tidak valid secara permisif. Sebuah block di dalam paragraf atau button di dalam button lain dapat menghasilkan DOM yang di-parse berbeda dari struktur yang dikeluarkan React. Perbaiki semantik dan nesting, lalu verifikasi dengan validasi HTML dan inspeksi DOM. Sebuah Effect bukanlah perbaikan untuk struktur yang tidak valid.
Jika kegagalan hanya terjadi pada edge-cache hit, bandingkan respons origin dan edge lalu nonaktifkan transformasi yang menulis ulang HTML. Jika hanya terjadi dengan ekstensi, reproduksi di profil bersih dan identifikasi apa yang diubah ekstensi sebelum React. Aplikasi dapat mengukur dampak tersebut, tetapi tidak boleh menyembunyikan semua mismatch aplikasi yang sebenarnya hanya karena ada ekstensi yang tidak terkontrol. Analisis skrip pihak ketiga dengan cara yang sama: hapus dari jalur awal satu per satu dan identifikasi penulisan DOM pertama.
Langkah 5: pilih escape hatch berdasarkan biayanya.
useEffect tepat untuk data lingkungan yang hanya dapat dibaca setelah hidrasi, tetapi ini membuat render kedua. dynamic dengan ssr: false tepat untuk komponen pihak ketiga lokal yang tidak dapat dieksekusi di server dan tidak membawa konten awal atau SEO yang penting. Mengubah seluruh halaman menjadi client-only rendering mengorbankan prerendering dan memperbesar periode layar kosong. suppressHydrationWarning hanya berfungsi sebagai escape hatch dangkal (shallow), dan React tidak menambal teks yang disembunyikan. Ini untuk perbedaan terisolasi yang tidak dapat dihindari, bukan perbaikan untuk zona waktu, ID acak, tema, atau data basi.
Langkah 6: buktikan perbaikan dengan matriks kegagalan.
Cakup setidaknya dua lokal, dua zona waktu, tema terang dan gelap, status masuk (signed-in) dan anonim, cache hit dan miss, JavaScript normal dan tertunda, profil bersih, serta ekstensi yang dikenal. Lakukan pemuatan ulang penuh untuk setiap kasus. Pastikan tidak ada recoverable hydration error yang terjadi, subtree penting tidak diganti, perilaku fokus dan event tetap benar, waktu dan tema diperbarui pada titik yang diinginkan, dan tata letak tidak melompat secara visual.
Tambahkan langkah code review untuk Date.now, Math.random, toLocaleString implisit, window atau localStorage dalam render, nesting berbahaya, dan suppressHydrationWarning yang luas. Ini mencegah insiden yang telah diperbaiki muncul kembali melalui kelas kesalahan yang sama.
Contoh Jawaban Berkualitas Tinggi
"Pertama-tama saya akan membatasi insiden pada pemuatan dokumen awal. Next.js dapat melakukan prerender Client Component pada permintaan awal. Setelah browser menerima HTML, React harus menghasilkan tree yang sama dari input awal yang sama sebelum memasang handler. Komponen ini membaca localStorage, menggunakan zona waktu default browser, dan membuat ID acak selama render, sehingga ketiga nilai tersebut dapat berbeda dari server. Struktur rich-text juga dapat diperbaiki oleh browser sebelum React melihatnya.
Saya akan mengambil satu peristiwa nyata dan menangkap full component stack, deployment, lokal, timeZone, sumber tema, dan status cache. Saya akan menyimpan respons jaringan dan membandingkannya dengan DOM sebelum React dimulai. Jika respons sudah salah, saya akan memeriksa snapshot server dan CDN. Jika parsing mengubahnya, saya akan memeriksa nesting yang tidak valid, ekstensi, dan skrip awal. Jika berubah hanya saat React dimulai, saya akan membandingkan props klien pertama dan percabangan lingkungan.
Untuk perbaikannya, server akan menyelesaikan lokal, timeZone, dan tema awal dari cookie atau profil, memformat updatedLabel, dan meneruskannya bersama waktu ISO. Render klien pertama akan menggunakan nilai-nilai tersebut secara persis. Saya akan mengganti ID acak dengan useId dan memperbaiki semantik HTML. Informasi browser yang tidak diketahui oleh server akan dimulai dengan placeholder stabil dan diperbarui dalam Effect. Data bisnis akan dimulai dari snapshot server yang diserialisasi dan di-refresh di latar belakang setelah hidrasi.
Saya tidak akan menonaktifkan SSR secara global atau menyembunyikan peringatan yang dapat diperbaiki. Saya akan menggunakan ssr: false lokal hanya untuk leaf pihak ketiga khusus browser, dan hanya menyembunyikan perbedaan tampilan satu tingkat yang tidak dapat dihindari. Terakhir, saya akan menguji cold load production di seluruh kombinasi lokal, zona waktu, tema, cache, jaringan lambat, dan browser bersih, memverifikasi tidak ada error #418, penggantian subtree, hilangnya fokus, atau flash visual."
Kesalahan Umum
- Mengasumsikan
"use client"berarti tidak ada HTML server. Client Component tetap dapat di-prerender pada pemuatan awal. - Menggunakan
typeof windowdi JSX untuk me-render dua UI. Cabang server dan render pertama browser dapat berbeda secara alami. - Memindahkan setiap nilai ke dalam Effect dan menganggapnya selesai. Ini dapat menunda mismatch sambil menambahkan render kedua, konten kosong, pergeseran tata letak, dan pengalaman jaringan lambat yang lebih buruk.
- Menambahkan
suppressHydrationWarningke root yang luas. Ini bersifat dangkal dan tidak membuat React menambal teks yang tidak cocok. - Mengubah seluruh halaman menjadi
ssr: falsesetelah melihat error production. Ini menghilangkan nilai prerendering tanpa menjelaskan akar masalahnya. - Hanya membandingkan View Source dengan DOM setelah hidrasi. Tindakan tersebut mengabaikan DOM yang di-parse browser sebelum React dimulai.
- Hanya menguji local development dan navigasi klien. Production build, full reload, edge cache, zona waktu, atau ekstensi mungkin diperlukan untuk memicu kesalahan awal.
- Berhenti ketika konsol sudah hening. Verifikasi juga tidak ada penggantian, handler yang salah, hilangnya fokus, flash visual, atau data bisnis yang salah.
Pertanyaan Lanjutan dan Tanggapan
Mengapa tidak menambahkan suppressHydrationWarning ke setiap timestamp?
Ini adalah escape hatch satu tingkat, dan React tidak menambal teks yang disembunyikan untuk Anda. Jika timestamp berbeda karena kedua lingkungan menggunakan zona waktu default yang berbeda, penentuan locale dan timeZone yang eksplisit atau nilai terformat bersama dapat memperbaiki penyebabnya. Gunakan penyembunyian hanya jika produk menerima nilai pasca-hidrasi yang sengaja dibuat berbeda dan perbedaan tersebut benar-benar tidak dapat dihilangkan. Verifikasi perilaku visual dan apa yang dibaca oleh teknologi asistif (assistive technology).
Bagaimana Anda memilih antara useEffect dan ssr: false?
Jika komponen memiliki shell yang stabil dan konten prerender yang berharga, tetapi satu label bergantung pada informasi browser, pertahankan SSR dan perbarui bagian kecil itu setelah hidrasi. Jika seluruh komponen leaf bergantung pada library pihak ketiga yang tidak dapat berjalan di server, tidak memiliki output prerender yang berguna, dan dapat menyediakan status pemuatan dengan ukuran stabil, nonaktifkan SSR secara lokal. Keputusan ini mengikuti nilai konten, batas dependensi, dan biaya visual, bukan opsi mana pun yang membuat peringatan menghilang paling cepat.
Bagaimana HTML yang tidak valid dapat merusak hidrasi ketika kedua lingkungan menjalankan kode React yang sama?
Server mengirimkan string, dan browser menyusun serta memperbaiki DOM sesuai dengan aturan parsing HTML. Nesting yang tidak valid dapat ditutup secara otomatis, dipindahkan, atau dihapus. Oleh karena itu, React mengambil alih tree yang telah diperbaiki, bukan tree yang tampaknya dijelaskan oleh string asli. Bandingkan response body dengan DOM pra-React, lalu perbaiki semantiknya dan validasi HTML.
Bagaimana Anda menambahkan observabilitas ketika kegagalan khusus production bersifat intermiten?
Kumpulkan recoverable error atau kode lengkap, component stack, route, versi deployment, lokal, timeZone, sumber tema, status cache, dan tipe browser dengan sampling dan pemfilteran privasi. Catat digest atau versi yang tidak dapat dibalik (nonreversible) untuk input first-render penting sehingga snapshot server dan klien dapat dibandingkan tanpa mencatat nilainya secara langsung. Kategorikan (slice) metrik berdasarkan route, versi, dan lingkungan. Setelah perbaikan, konfirmasikan bahwa tingkat error mencapai nol dan penggantian subtree, interaksi, serta metrik visual tidak mengalami regresi.