React.memo — React

Default React: parent re-render → SEMUA child ikut re-render, walaupun props mereka gak berubah. Kebanyakan kasus ini OK (React cepat). Tapi pas ada child yang

Default React: parent re-render → SEMUA child ikut re-render, walaupun props mereka gak berubah. Kebanyakan kasus ini OK (React cepat). Tapi pas ada child yang RENDER-nya mahal — misalnya komponen tabel 1000 row, chart kompleks — re-render sia-sia ngabisin frame budget. React.memo = wrap komponen jadi "hanya re-render kalau props beneran berubah" (pakai shallow comparison). Kombinasi memo + useCallback (untuk function props) + useMemo (untuk object/array props) = trio optimisasi yang harus dipake bareng biar efektif.

💡 Salah satu = sia-sia. Pakai memo doang? Function/object prop baru tiap render → memo gagal compare → tetap re-render. Pakai useCallback doang? Child gak di-memo → tetep re-render karena parent. Tiganya saling tergantung. Kalau salah pakai = tambah complexity tanpa benefit.

const ExpensiveList = memo(function ExpensiveList({ items }) {
  console.log("List dirender")
  return (
    <ul>
      {items.map(item => <li key={item}>{item}</li>)}
    </ul>
  )
})

function App() {
  const [count, setCount] = useState(0)
  const items = useMemo(() => ["A", "B", "C"], [])  // ← stable reference!

  return (
    <div>
      <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
      <ExpensiveList items={items} />  {/* gak re-render saat count++ */}
    </div>
  )
}

Klik tombol → count berubah → App re-render. Tapi ExpensiveList SKIP re-render karena items reference sama (thanks to useMemo).

Cara Kerja memo

  1. Saat parent re-render, React bandingkan props baru vs lama (shallow comparison)
  2. Props sama (reference identik untuk object/array, value sama untuk primitive) → SKIP re-render
  3. Props berbeda → re-render seperti biasa

Gotcha: Object/Array/Function Props

// ✗ BUG — object literal beda reference tiap render = memo gagal
function App() {
  return <ExpensiveList items={["A", "B"]} />  // array baru tiap render!
}

// ✗ BUG — function inline juga beda reference
function App() {
  return <ExpensiveList onItemClick={() => console.log("click")} />
}

// ✓ FIX — useMemo + useCallback
function App() {
  const items = useMemo(() => ["A", "B"], [])
  const handleClick = useCallback(() => console.log("click"), [])
  return <ExpensiveList items={items} onItemClick={handleClick} />
}

Custom Comparison Function

// Default shallow compare — kalau gak cukup, custom
const ExpensiveItem = memo(
  function ExpensiveItem({ user }) { /* ... */ },
  (prev, next) => prev.user.id === next.user.id  // hanya compare ID
)

Return true = props sama (skip re-render), false = beda (re-render).

🎭 Analogi sehari-hari

memo itu kayak resepsionis hotel yang inget tamu lama. Tamu pulang → checkout → resepsionis catat data. Pas tamu balik 2 minggu kemudian, resepsionis cek catatan: "data sama persis kayak dulu? Kasih kunci kamar lama, gak perlu register ulang (skip re-render)." Tapi kalau tamu ganti nomor HP/alamat (props berubah), resepsionis register ulang dari awal (re-render). Untuk hotel kecil dengan 5 tamu/hari, register ulang gak masalah (default React cukup cepat). Untuk hotel besar dengan 1000 tamu/hari, optimisasi check-in (memo + reference stability) bikin antrian gak panjang (frame budget gak abis).

⚠️ Jebakan yang sering ditemui

🎯 Wrap dengan memo atau biarin?

  • Default: GAK pakai memo. React cukup cepat.
  • Component render BANYAK item (table 100+ row) → memo
  • Component pakai library berat internally (chart, video player) → memo
  • Component yang sering jadi child component dengan state berubah cepatmemo + useCallback di parent
  • Component sederhana (50-100 elements) → biarin, gak butuh memo
  • List item dengan banyak propmemo per item bisa drastis improve perf

Aturan: profile dulu pake React DevTools, optimisasi setelah ada bukti. React Compiler (R19+) auto-handle, jadi memo manual makin jarang.

TL;DR: memo(Component) = wrap komponen jadi skip re-render kalau props gak berubah (shallow compare). WAJIB combo dengan useCallback + useMemo di parent untuk function/object props (kalau gak, reference baru tiap render = memo gagal). Cuma berguna untuk komponen yang RENDER-nya mahal. Default React cepat — pakai memo cuma setelah profiler nunjukin masalah. R19 + React Compiler bisa auto-handle ini.

Yang akan kamu pelajari