Reactjs Refs Useimperativehandle Forwardref DOM Access Patterns
Definisi
ref di React adalah pegangan ke node DOM atau instance komponen, yang tidak memicu render saat diubah. useRef membuat objek { current } yang persisten antar render. forwardRef memungkinkan komponen meneruskan ref ke child, dan useImperativeHandle membatasi API imperatif yang diekspos ke parent.
Kapan dipakai
Pakai ref untuk hal yang bukan merupakan state UI: fokus input, scroll ke elemen, mengukur ukuran DOM, menyimpan timer/id interval, atau memanggil method imperatif komponen anak (misal reset() di form). Jangan pakai ref untuk data yang harus memicu re-render — itu tugas state.
Cara kerja
useRef dasar
const inputRef = useRef<HTMLInputElement>(null);
function focus() {
inputRef.current?.focus();
}
return <input ref={inputRef} />;forwardRef + useImperativeHandle
import { forwardRef, useImperativeHandle, useRef } from 'react';
type FormHandle = { reset: () => void };
const Form = forwardRef<FormHandle>((props, ref) => {
const valueRef = useRef('');
useImperativeHandle(ref, () => ({
reset: () => {
valueRef.current = '';
},
}));
return <input ref={valueRef} />;
});
// Pemakaian
const formRef = useRef<FormHandle>(null);
<Form ref={formRef} />;
formRef.current?.reset();useImperativeHandle hanya mengekspos reset, bukan seluruh node input, sehingga parent tidak bisa asal manipulasi DOM dalam.
Struktur alur
Contoh pengukuran
const boxRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const width = boxRef.current?.offsetWidth;
console.log('lebar:', width);
}, []);
return <div ref={boxRef} />;Catatan implementasi
- Baca
ref.currentdi event handler atauuseEffect, bukan saat render (saat render, node bisa belum terpasang). useImperativeHandlesebaiknya tipis: ekspos hanya aksi yang perlu, jangan seluruh DOM.- Untuk list dinamis, hindari satu ref menampung banyak node; pakai
useRefberisiMapatau callback ref. - Bersihkan timer/intervals di
useEffectcleanup supaya tidak bocor.
Kesalahan umum
- Stale ref: mengakses
ref.currentsaat render pertama sebelum node mount, hasilnyanull. - Ref dipakai sebagai state: mengubah
ref.currentlalu mengharapkan UI update — tidak akan terjadi, pakaiuseState. - Lupa cleanup: interval atau event listener di ref tidak dibersihkan, menyebabkan leak.
- Terlalu banyak imperatif: menghindari state lewat ref membuat alur data jadi tidak terprediksi dan sulit di-debug.