Episode ini membahas profiling dengan React DevTools dan browser tools, memoization memakai useMemo dan useCallback untuk komputasi mahal, virtualization untuk daftar panjang, serta pola menghindari re-render yang tidak perlu dalam rendering.

Aplikasi yang lambat adalah aplikasi yang kehilangan pengguna. Episode 15 membahas performance optimization dari sudut yang benar: ukur dulu, optimalkan kemudian. Tanpa pengukuran, optimasi hanyalah tebakan yang menambah kompleksitas.
Kita akan memakai React DevTools dan browser tools untuk profiling, menerapkan memoization dengan useMemo dan useCallback, menggunakan virtualization untuk daftar yang sangat panjang, dan menutup dengan pola menghindari re-render yang tidak perlu.
React DevTools punya tab Profiler yang merekam render tiap komponen, lama render, dan penyebabnya. Alur kerja yang benar:
catat baseline -> lakukan interaksi -> berhenti rekam -> cari render mahal -> optimasi -> ukur ulangPertanyaan pertama saat menemukan komponen lambat bukan "bagaimana mengoptimasi", tapi "apakah komponen ini perlu re-render". Profiler menjawab pertanyaan ini dengan bukti, bukan perasaan.
Untuk masalah yang melibatkan layout dan painting, pakai Performance panel browser. Rekam interaksi, lalu periksa flame chart untuk menemukan fungsi yang makan waktu. Kombinasikan dengan tab Rendering yang menandai elemen yang di-paint ulang setiap frame.
Episode 6 sudah memperkenalkan kedua hooks ini. Di episode 15 kita melihat kapan ia benar-benar bernilai: komputasi mahal yang dijalankan pada setiap render:
import { useMemo } from "react"
function Statistik({ transaksi }) {
const total = useMemo(() => {
return transaksi.reduce((acc, t) => acc + t.nilai, 0)
}, [transaksi])
return <p>Total: {total}</p>
}useMemo(() => reduce(...), [transaksi]) menghitung ulang hanya saat transaksi berubah. Tanpa itu, reduce berjalan setiap render meskipun data tidak berubah.
useCallback menjaga referensi fungsi tetap stabil. Nilai nyatanya terasa saat fungsi diteruskan ke komponen yang dibungkus memo:
import { memo, useCallback, useState } from "react"
const Tombol = memo(function Tombol({ onClick }) {
return <button onClick={onClick}>Klik</button>
})
function App() {
const [jumlah, setJumlah] = useState(0)
const handleKlik = useCallback(() => setJumlah((n) => n + 1), [])
return (
<div>
<Tombol onClick={handleKlik} />
<p>{jumlah}</p>
</div>
)
}memo membuat Tombol hanya re-render saat props berubah. Tanpa useCallback, handleKlik berganti referensi tiap render dan memo menjadi sia-sia. Kedua teknik bekerja berpasangan.
Merender 10.000 item dalam satu map membuat browser kewalahan: ribuan node DOM dibuat sekaligus. Virtualization menjawabnya dengan hanya merender item yang terlihat layar:
npm install react-windowimport { FixedSizeList } from "react-window"
function DaftarBesar({ items }) {
return (
<FixedSizeList
height={400}
width="100%"
itemCount={items.length}
itemSize={35}
>
{({ index, style }) => (
<div style={style}>{items[index].nama}</div>
)}
</FixedSizeList>
)
}FixedSizeList dari react-window hanya merender item yang terlihat dalam viewport berukuran height={400}. Saat pengguna menggulir, item lama dibuang dan item baru dirender — ratusan node, bukan ribuan. Untuk ukuran item bervariasi, gunakan VariableSizeList.
State yang dideklarasikan terlalu tinggi menyebabkan seluruh subtree re-render padahal hanya satu bagian yang berubah. Pindahkan state sedekat mungkin dengan komponen yang memakainya:
// buruk: state di atas menyebabkan seluruh daftar re-render
function App() {
const [teks, setTeks] = useState("")
return (
<div>
<input value={teks} onChange={(e) => setTeks(e.target.value)} />
<DaftarBesar items={items} />
</div>
)
}
// baik: input dibungkus komponen sendiri
function InputNama() {
const [teks, setTeks] = useState("")
return <input value={teks} onChange={(e) => setTeks(e.target.value)} />
}Memindahkan state ke komponen InputNama membuat DaftarBesar tidak ikut re-render setiap ketikan. Aturan ini sering memberi perbaikan terbesar dengan perubahan terkecil.
Untuk kasus di mana state tidak bisa dipindah, bungkus bagian yang stabil sebagai children agar React tidak merendernya ulang. Gabungkan teknik ini dengan memo dan hasil pengukuran Profiler untuk keputusan yang tepat.
Warning
Jangan mem-memoize semuanya. memo, useMemo, dan useCallback menambah overhead komparasi dan membingungkan pembaca kode. Ukur dengan Profiler, optimalkan yang benar-benar lambat, lalu ukur ulang.
Episode 15 menyelesaikan toolkit performance React: profiling dengan React DevTools dan browser tools, memoization dengan useMemo, useCallback, dan memo, virtualization dengan react-window, serta pola menghindari re-render dengan memindahkan state ke bawah.
Inti yang harus dibawa pulang:
useMemo untuk komputasi mahal; useCallback untuk referensi stabil.memo dan useCallback bekerja berpasangan untuk menghentikan re-render anak.Di episode 16 selanjutnya kita akan membahas testing & quality — unit testing dengan Jest dan React Testing Library, snapshot testing, integration testing untuk perilaku komponen, serta E2E testing dengan Cypress atau Playwright. Kualitas kode dijamin, bukan diharapkan.