React memberi Anda dua cara untuk menjaga data tetap hidup di dalam sebuah komponen: useState dan useRef. Sekilas keduanya tampak serupa. Keduanya mengembalikan sesuatu yang dapat Anda baca, keduanya bertahan melewati re-render, dan keduanya memungkinkan Anda mengingat sebuah nilai dari satu klik ke klik berikutnya. Namun, jika Anda salah memilih, Anda akan berakhir dengan layar yang menolak untuk diperbarui atau rentetan re-render yang tidak perlu secara terus-menerus. Pilihannya bukan tentang sintaksis. Ini tentang apakah React perlu mengetahuinya.

Apa yang Sebenarnya Dilakukan oleh Setiap Hook

useState adalah jalur komunikasi resmi React dengan sebuah komponen. Saat Anda memanggilnya, Anda akan mendapatkan sebuah nilai dan fungsi setter. React melacak nilai tersebut sebagai bagian dari identitas komponen. Saat setter dijalankan, React berkata, “Ada sesuatu yang berubah,” dan menjadwalkan render baru agar layar dapat diperbarui.

Di sisi lain, useRef tidak lebih dari sekadar objek JavaScript biasa dengan properti current. React berjanji untuk memberikan referensi objek yang persis sama pada setiap render. React tidak memantau apa yang ada di dalamnya. Mengubah (mutating) someRef.current terjadi secara diam-diam. React tidak akan bereaksi.

Keheningan itulah intinya. Ref adalah sebuah escape hatch, bukan pengganti state.

Perbedaan Rendering

Jika Anda mengubah state, komponen akan melakukan re-render. Ini adalah perilaku yang diharapkan oleh kebanyakan pemula, dan inilah yang Anda inginkan ketika data baru harus muncul di layar. Sebuah penghitung (counter), kolom formulir, daftar pengguna yang diambil (fetched)—jika pengguna melihatnya, kemungkinan besar itu adalah bagian dari state. Seluruh aliran data React dibangun di sekitar gagasan bahwa perubahan state memberi tahu renderer untuk menyinkronkan DOM.

Jika Anda mengubah sebuah ref, tidak ada yang terjadi secara visual. Variabel tersebut diperbarui secara instan dan sinkron, tetapi komponen tidak melakukan re-render. Hal ini membuat ref ideal untuk nilai-nilai yang mendukung mekanisme internal komponen tanpa menjadi bagian dari output visual. Contohnya seperti ID timer, snapshot prop sebelumnya, atau handle DOM langsung. UI tidak peduli dengan interval ID yang menjalankan autoplay carousel; UI hanya peduli slide mana yang terlihat. Interval ID tersebut seharusnya berada di dalam sebuah ref.

Kapan State Adalah Alat yang Tepat

Gunakan useState kapan pun sebuah nilai merupakan bagian dari tampilan UI Anda.

Kolom input adalah contoh yang jelas. Jika pengguna mengetik alamat email dan Anda perlu memvalidasinya serta menampilkan pesan kesalahan di bawah kotak tersebut, string email itu membutuhkan state. Logika validasi dan banner kesalahan keduanya bergantung pada nilai terbaru, dan React hanya tahu untuk memperbarui banner tersebut karena state memicu re-render.

Penghitung (counts) dan toggle adalah hal umum lainnya. Tombol yang menambah skor, flag buka/tutup modal, indeks tab—semuanya mengalir melalui state karena output render berubah seiring dengan nilainya. Bahkan nilai turunan (derived values), seperti daftar yang difilter yang bergantung pada string pencarian, biasanya dimulai dengan state karena nilai sumbernya terlihat oleh pengguna.

Ada juga nuansa waktu yang perlu dipahami. Pembaruan state bersifat asinkron dan dikelompokkan (batched). Jika Anda memanggil setCount(count + 1) tiga kali di dalam satu event handler, React tidak melakukan render tiga kali. React mengelompokkannya menjadi satu pembaruan tunggal. Variabel count di dalam fungsi yang sedang berjalan juga akan tetap usang (stale) hingga render berikutnya. Pengelompokan (batching) ini adalah sebuah fitur. Ini menjaga aplikasi tetap cepat. Namun, ini berarti Anda tidak dapat mengharapkan variabel state mencerminkan nilai baru pada baris berikutnya.

Kapan Ref Menyelamatkan Keadaan

Gunakan useRef untuk urusan teknis internal, bukan