useRef Adalah: Cara Kerja Hook useRef di React untuk Mengakses DOM dan Menyimpan Nilai Tanpa Re-render
useRef adalah hook React untuk mengakses elemen DOM langsung dan menyimpan nilai yang bertahan antar render tanpa memicu re-render. Pahami perbedaannya dengan useState lewat contoh interaktif.
Pembuat Hyper Sheets & BelajarWeb.dev
useRef adalah hook bawaan React yang mengembalikan sebuah “kotak” yang nilainya bertahan antar render, dan yang membuatnya istimewa: mengubah isi kotak itu TIDAK memicu re-render komponen. Kotak ini punya satu properti bernama current, dan kamu bebas membaca serta menuliskan apa pun ke sana. useRef punya dua kegunaan utama yang akan kamu pakai berulang kali: (1) mengakses elemen DOM secara langsung, misalnya memfokuskan sebuah input, dan (2) menyimpan nilai yang perlu “diingat” antar render tapi tidak boleh menyebabkan tampilan digambar ulang, seperti id sebuah timer.
Kalau useState adalah cara React membuat UI reaktif terhadap data, useRef adalah pasangannya untuk hal-hal “di pinggir” React, nilai yang bertahan tapi tidak perlu ditampilkan, atau akses langsung ke node DOM yang React biasanya sembunyikan dari kamu. Di panduan ini kamu akan memahami useRef dari nol: apa isi objek ref, dua kegunaan utamanya, kenapa mengubah ref.current tidak menggambar ulang layar, perbandingan lengkap dengan useState, sampai kesalahan umum, lengkap dengan playground yang bisa kamu klik-klik sendiri.
Apa Itu useRef di React?
useRef adalah hook yang membuat sebuah objek dengan satu properti, current, yang isinya tetap sama (bertahan) selama komponen hidup, dan mengubahnya tidak menyebabkan komponen dirender ulang. Kamu memanggilnya dengan sebuah nilai awal, dan ia mengembalikan objek ref:
import { useRef } from 'react'
function Contoh() {
const myRef = useRef(0)
// ↑ objek ref ↑ nilai awal untuk .current
console.log(myRef.current) // 0 di render pertama
return <p>Cek console</p>
}
Objek yang dikembalikan bentuknya sesederhana ini: { current: 0 }. Kamu membaca nilainya lewat myRef.current dan mengubahnya dengan menetapkan myRef.current = nilaiBaru. Yang penting dipahami, React memberikan objek yang sama persis di setiap render, jadi apa pun yang kamu simpan di .current akan tetap ada di render berikutnya, tidak direset seperti variabel biasa.
Perbedaan besarnya dengan useState: memanggil setState memicu render ulang, sedangkan menetapkan ref.current sama sekali tidak. Ref itu diam-diam menyimpan nilai; ia tidak pernah “memberi tahu” React bahwa sesuatu berubah.
Panduan ini mengasumsikan kamu sudah paham dasar React: apa itu component, JSX, dan useState. Kalau belum, baca dulu panduan belajar React dari nol dan useState adalah supaya fondasinya kuat. Memahami kapan React merender ulang komponen, yang dibahas di materi useState, akan sangat membantu memahami sisi “tidak re-render” dari useRef.
Kegunaan Pertama: Mengakses Elemen DOM
Kegunaan useRef yang paling umum adalah mendapatkan akses langsung ke sebuah elemen DOM asli, misalnya untuk memanggil focus(), mengukur ukurannya, atau menggulir ke posisinya. Biasanya di React kamu tidak menyentuh DOM sama sekali; kamu mengubah state dan React yang mengurus DOM. Tapi sesekali kamu butuh node DOM sungguhan, dan ref adalah jembatannya.
Caranya dua langkah: buat ref, lalu pasang ke elemen lewat atribut ref.
import { useRef } from 'react'
function KotakCari() {
const inputRef = useRef(null)
function fokuskan() {
inputRef.current.focus() // .current sekarang adalah node <input> asli
}
return (
<div>
<input ref={inputRef} placeholder="Cari..." />
<button onClick={fokuskan}>Fokus input</button>
</div>
)
}
Saat React memasang elemen input ke layar, ia otomatis mengisi inputRef.current dengan node DOM asli dari input tersebut. Sejak itu, kamu bisa memanggil method DOM apa pun di atasnya, focus(), scrollIntoView(), select(), dan lainnya. Nilai awal useRef(null) dipakai karena node-nya belum ada saat render pertama; React yang mengisinya setelah elemen benar-benar terpasang.
Kegunaan Kedua: Menyimpan Nilai yang Bertahan Tanpa Re-render
Kegunaan kedua useRef adalah menyimpan sebuah nilai yang perlu bertahan antar render, persis seperti state, tapi yang perubahannya tidak boleh (atau tidak perlu) memicu render ulang. Contoh klasiknya: id dari sebuah timer, nilai sebelumnya sebuah state, atau penanda apakah sebuah efek sudah pernah berjalan.
Kenapa tidak pakai variabel biasa saja? Karena variabel biasa (let x = 0 di dalam komponen) akan direset ke nilai awal setiap kali komponen dirender ulang, ia tidak mengingat apa pun. Ref mengingatnya.
import { useRef } from 'react'
function Stopwatch() {
const timerId = useRef(null)
function mulai() {
timerId.current = setInterval(() => {
console.log('tik')
}, 1000)
}
function berhenti() {
clearInterval(timerId.current) // id-nya masih ada, bahkan setelah render lain
}
return (
<div>
<button onClick={mulai}>Mulai</button>
<button onClick={berhenti}>Berhenti</button>
</div>
)
}
Id timer disimpan di timerId.current. Ia tidak memengaruhi tampilan, jadi tidak masuk akal menyimpannya di state (yang akan memicu render sia-sia). Tapi ia harus bertahan supaya tombol “Berhenti” bisa membaca id yang sama yang dibuat tombol “Mulai”, dan ref melakukan itu dengan sempurna.
Coba Sendiri
Dirender: 1×Demo 1, Akses DOM
Klik tombolnya, dan ref langsung memfokuskan input di bawah, tanpa menyentuh state.
Demo 2, Nilai tanpa re-render
Tombol kiri menaikkan nilai di dalam ref, tapi angka di layar TIDAK ikut naik, karena ubah ref tidak memicu render. Tombol tengah memaksa render, dan nilai ref yang sebenarnya baru muncul. Bandingkan dengan counter state di kanan yang selalu update tiap klik.
Counter di dalam ref
0
nilai asli ref: 0 (tampilan bisa tertinggal)
ubah ref → tidak re-render
Counter di dalam state
0
layar selalu sinkron dengan nilai state
ubah state → re-render
const inputRef = useRef(null) // → inputRef.current.focus()
const countRef = useRef(0) // countRef.current++ (tak re-render)
const [n, setN] = useState(0) // setN(...) → re-renderCoba mainkan demo di atas. Di Demo 2, klik “Tambah (ref)” beberapa kali, nilai di dalam ref benar-benar naik di memori, tapi angka di layar diam saja. Baru setelah kamu menekan “Paksa re-render” (yang diam-diam memakai useState), React menggambar ulang dan nilai ref yang sebenarnya muncul. Bandingkan dengan counter state di kanan yang selalu update setiap klik. Itulah inti perbedaan keduanya, terlihat langsung di depan matamu.
useRef vs useState: Tabel Perbandingan
Karena keduanya sama-sama “mengingat” nilai antar render, pemula sering bingung kapan memakai yang mana. Tabel ini merangkum perbedaan intinya:
useRef |
useState |
|
|---|---|---|
| Memicu re-render saat diubah? | Tidak | Ya |
| Cara mengubah | ref.current = nilai |
setState(nilai) |
| Bertahan antar render? | Ya | Ya |
| Kapan dipakai | Akses DOM, nilai yang tak perlu tampil (id timer, nilai sebelumnya) | Data yang tampil di layar dan berubah karena interaksi |
| Boleh diubah kapan saja? | Ya, di event handler/efek | Lewat setter, memicu render |
Cara cepat memutuskan: kalau perubahan nilai itu harus terlihat di layar, pakai useState. Kalau nilai itu hanya “catatan sampingan” yang tidak ditampilkan, atau kamu butuh node DOM asli, pakai useRef. Kalau kamu masih menimbang antara data internal dan data dari induk, panduan props vs state di React melengkapi gambaran ini dari sisi yang berbeda.
Hubungan useRef dengan useEffect
Ref dan useEffect sering berpasangan. Karena ref.current yang menunjuk ke DOM baru terisi setelah elemen terpasang, tempat teraman untuk membaca ukuran atau mengatur fokus otomatis saat komponen muncul adalah di dalam useEffect:
import { useRef, useEffect } from 'react'
function FormLogin() {
const emailRef = useRef(null)
useEffect(() => {
emailRef.current.focus() // fokus otomatis begitu form muncul
}, [])
return <input ref={emailRef} placeholder="Email" />
}
Ref juga sering dipakai untuk menyimpan nilai sebelumnya sebuah state, dengan memperbaruinya di dalam efek setelah setiap render. Kalau kamu belum kuat soal efek, mundur sebentar ke useEffect adalah, memahami kapan efek berjalan membuat pola-pola ref di atas jauh lebih masuk akal.
Kesalahan Umum Pemula dengan useRef
Sebelum lanjut, kenali jebakan yang paling sering menimpa pemula:
- Menyimpan data yang harus tampil di layar di dalam ref, lalu bingung kenapa layar tidak update saat
ref.currentberubah. Kalau nilainya perlu terlihat dan berubah, itu tugasuseState. - Membaca
ref.currentyang menunjuk DOM terlalu dini, misalnya langsung di badan komponen atau di render pertama sebelum elemen terpasang. Node-nya masihnullsaat itu; baca di event handler atauuseEffect. - Mengira mengubah
ref.currentakan menggambar ulang komponen. Tidak akan. Ini fitur, bukan bug, justru itu alasanuseRefdipakai. - Memakai ref untuk menghindari “kerepotan” state pada nilai yang sebenarnya reaktif. Kalau UI harus bereaksi terhadap perubahan, state adalah alat yang benar.
Kamu punya const hitung = useRef(0), lalu menaikkannya dengan hitung.current++ saat tombol diklik. Apa yang terjadi pada komponen?
FAQ Seputar useRef
Apa itu useRef dengan bahasa sederhana?
useRef adalah “kotak” yang React sediakan untuk komponenmu. Kotak ini punya satu laci bernama current tempat kamu bisa menaruh apa saja, dan isinya tetap ada selama komponen hidup, tidak hilang tiap render. Keistimewaannya: mengubah isi kotak tidak membuat React menggambar ulang tampilan. Dua kegunaan utamanya adalah memegang elemen DOM asli (untuk fokus, scroll, ukur) dan menyimpan nilai sampingan seperti id timer.
Apa bedanya useRef dan useState?
Keduanya sama-sama mengingat nilai antar render, tapi bedanya menentukan: mengubah state lewat setter membuat React merender ulang komponen sehingga tampilan ikut berubah, sedangkan mengubah ref.current sama sekali tidak memicu render. Pakai useState untuk data yang tampil di layar dan berubah karena interaksi; pakai useRef untuk akses DOM langsung atau nilai yang perlu bertahan tapi tidak perlu ditampilkan.
Apakah mengubah ref.current menyebabkan re-render?
Tidak. Ini justru inti dari useRef. Kamu bisa menaikkan, menimpa, atau membaca ref.current sesering apa pun tanpa React menggambar ulang komponen. Kalau kamu butuh perubahan sebuah nilai langsung tercermin di layar, gunakan useState, bukan useRef.
Kapan sebaiknya pakai useRef, bukan useState?
Pakai useRef ketika kamu butuh akses langsung ke elemen DOM (memfokuskan input, menggulir ke elemen, mengukur ukuran) atau ketika kamu perlu menyimpan nilai yang bertahan antar render tapi tidak perlu memicu tampilan berubah, seperti id setInterval, nilai state sebelumnya, atau penanda internal. Kalau perubahan nilai itu harus terlihat di layar, itu justru pertanda kamu butuh useState.
Sampai di sini, kamu sudah memahami inti useRef: ia adalah kotak dengan properti current yang bertahan antar render, dipakai untuk mengakses DOM langsung dan menyimpan nilai yang tidak boleh memicu render. Ingat satu ide utamanya, ubah ref tidak menggambar ulang layar, ubah state menggambar ulang layar, maka kamu akan selalu tahu alat mana yang tepat. Kalau ingin menulis useRef sungguhan dan melihat DOM merespons langsung di browser, lanjutkan ke materi useRef interaktif di learnhypersheets, kamu akan mempraktikkan fokus input dan menyimpan nilai antar render sendiri. Buka lagi playground di atas kapan pun kamu ragu, dan teruslah membangun!