Pernah nggak, kamu bikin aplikasi React yang udah keren banget secara tampilan — tapi pas dipakai, terasa lemot kayak internet warnet tahun 2005? 😅 Setiap kali user klik tombol atau isi form, komponen lain ikut-ikutan re-render padahal nggak ada hubungannya. Masalah ini bukan soal skill atau kurang bakat — ini soal optimasi performa React yang memang jarang diajarkan untuk pemula.
Di artikel ke-11 dari Seri Belajar React: React from Zero to Zorro ini, kita bakal bedah tiga hook dan utility bawaan React yang bisa bikin aplikasimu jauh lebih efisien: useMemo, useCallback, dan React.memo. Ketiganya adalah alat yang dipakai developer senior untuk mengontrol kapan sebuah komponen atau nilai perlu dihitung ulang — dan kapan tidak.
Re-render adalah proses React menggambar ulang komponen. Ini normal — tapi kalau terjadi terlalu sering dan tidak perlu, performa aplikasimu akan menurun drastis. useMemo, useCallback, dan React.memo adalah mekanisme untuk mencegah re-render yang tidak diperlukan dengan cara memoization — menyimpan hasil perhitungan agar tidak dihitung ulang setiap saat.
🧠 Kenapa Aplikasi React Bisa Jadi Lambat?
Bayangkan kamu punya toko kue. Setiap kali ada pelanggan baru masuk, kamu menghitung ulang semua stok dari awal, padahal stoknya belum berubah. Capek kan? Nah, React tanpa optimasi bekerja mirip seperti itu.
Secara default, setiap kali state atau props berubah pada sebuah komponen induk, semua komponen anak akan ikut di-render ulang — meskipun data yang mereka butuhkan tidak berubah sama sekali. Inilah yang disebut unnecessary re-render, dan ini adalah biang keladi utama aplikasi React yang terasa berat.
Masalah ini makin terasa ketika aplikasimu punya daftar panjang, perhitungan berat, atau banyak komponen bersarang. Di sinilah tiga alat kita berperan.
⚙️ Cara Kerja dan Contoh Praktis useMemo, useCallback & React.memo
Mari kita bahas satu per satu dengan contoh yang bisa langsung kamu praktikkan. Ingat, pemahaman terbaik datang dari menulis kode sendiri — bukan hanya membacanya!
useMemo — Simpan Hasil Perhitungan Berat
Anggap useMemo seperti catatan di buku tulis. Daripada menghitung ulang nilai yang sama setiap kali render, React menyimpan hasilnya dan hanya menghitung ulang jika dependensinya berubah.
Kapan dipakai? Ketika kamu punya fungsi yang hasilnya membutuhkan komputasi berat — seperti memfilter array ribuan item, menghitung total harga, dsb.
function ProductList({ products }) {
const [search, setSearch] = useState('');
// ✅ useMemo: filter hanya dihitung ulang jika 'search' atau 'products' berubah
const filteredProducts = useMemo(() => {
return products.filter(p =>
p.name.toLowerCase().includes(search.toLowerCase())
);
}, [products, search]); // ← dependency array
return (
<div>
<input value={search} onChange={e => setSearch(e.target.value)} />
<ul>{filteredProducts.map(p => <li key={p.id}>{p.name}</li>)}</ul>
</div>
);
}
[], nilai hanya dihitung sekali. Jika kamu lupa mengisinya dengan benar, kamu bisa mendapat bug yang susah di-debug. Gunakan plugin ESLint exhaustive-deps untuk bantuan!
useCallback — Stabilkan Referensi Fungsi
Di JavaScript, setiap kali komponen re-render, fungsi yang dibuat di dalamnya mendapat alamat memori baru — meskipun isinya sama persis. Ini masalah karena komponen anak yang menerima fungsi itu akan menganggapnya "berubah" dan ikut re-render.
useCallback memastikan fungsi punya referensi yang stabil — tidak berubah alamat memorinya — selama dependensinya belum berubah.
function ParentComponent() {
const [count, setCount] = useState(0);
// ❌ Tanpa useCallback: fungsi baru setiap render
// const handleClick = () => console.log('clicked');
// ✅ Dengan useCallback: referensi fungsi stabil
const handleClick = useCallback(() => {
console.log('Button diklik!');
}, []); // ← kosong karena tidak ada dependensi
return (
<div>
<button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
<ChildButton onClick={handleClick} />
</div>
);
}
React.memo — Lindungi Komponen dari Re-render Sia-sia
React.memo adalah Higher-Order Component (HOC) yang membungkus komponen kamu. Ia akan membandingkan props lama dan props baru secara shallow. Jika tidak ada yang berubah, komponen tersebut tidak akan di-render ulang.
Analoginya: seperti satpam pintu yang cek ID. Kalau ID-nya sama, nggak perlu masuk ulang.
// ✅ Bungkus komponen dengan React.memo
const ChildButton = React.memo(function ChildButton({ onClick }) {
console.log('ChildButton render');
return <button onClick={onClick}>Klik Saya</button>;
});
// Sekarang ChildButton TIDAK akan re-render saat ParentComponent re-render,
// SELAMA props 'onClick' tidak berubah referensinya (gunakan useCallback!)
🎯 Panduan Praktis: Kapan Harus Pakai Optimasi Performa React?
Sebelum kamu semangat membungkus semua komponen dengan React.memo dan menyemprot seluruh kode dengan useMemo — tunggu dulu! Ada pepatah bijak di dunia programming: "premature optimization is the root of all evil".
Optimasi berlebihan justru bisa membuat kode lebih sulit dibaca dan dipelihara, serta menambah overhead memori. Gunakan ketiga alat ini sesuai kebutuhan.
🔍 Panduan Penggunaan yang Tepat
- Kamu punya fungsi filtrasi/sorting pada data besar (ribuan item)
- Perhitungan matematika kompleks yang dipanggil berulang
- Transformasi data yang hasilnya dipakai di banyak tempat
- Fungsi dikirim sebagai props ke komponen anak yang pakai
React.memo - Fungsi dipakai sebagai dependensi di hook lain (useEffect, useMemo)
- Komponen sering di-render ulang oleh parent, tapi propsnya jarang berubah
- Komponen itu mahal untuk di-render (punya banyak elemen/logika)
useMemo dan useCallback itu sendiri punya biaya memori dan komputasi (untuk menyimpan cache dan membandingkan dependensi). Untuk komponen sederhana dengan re-render yang jarang, tidak menggunakan optimasi justru lebih efisien. Ukur dulu, optimasi kemudian. Gunakan React DevTools Profiler untuk menemukan bottleneck nyata.
Seri Belajar React: React from Zero to Zorro
Artikel ini adalah bagian ke-11 dari 16. Lihat daftar lengkap seri ini dan mulai belajar dari awal atau lanjutkan dari artikel sebelumnya.
No comments:
Post a Comment