Keys & Reconciliation — React

Pas user hapus item dari shopping cart, React harus tahu MANA item yang dihapus — biar cuma 1 row yang di-remove dari DOM, bukan rebuild seluruh list. Pas user

Pas user hapus item dari shopping cart, React harus tahu MANA item yang dihapus — biar cuma 1 row yang di-remove dari DOM, bukan rebuild seluruh list. Pas user re-order todo list, React harus tahu MANA yang pindah ke mana — biar animasi smooth, state internal item gak ke-mix. Key prop ngasih identitas unik ke tiap list item, dipake React buat mecahkan teka-teki "mana yang sama, mana yang baru, mana yang pindah" pas re-render. Salah pilih key = bug subtle yang bikin pusing pas debug.

💡 Reconciliation = jantung performa React. Tiap render, React bikin Virtual DOM baru, bandingin sama yang lama (diff), update real DOM cuma yang berubah. key adalah hint kritis di proses diff list. Salah key = React rebuild item yang harusnya gak perlu, performa drop.

{items.map(item => (
  <li key={item.id}>{item.nama}</li>
))}

Aturan key:

Kenapa Index Buruk?

// ❌ Buruk jika list bisa berubah urutan
{items.map((item, index) => <li key={index}>{item}</li>)}

Bayangin list [A, B, C] dengan key index [0, 1, 2]. User hapus A → list jadi [B, C], key [0, 1]. React lihat:

Hasil: 2 update + 1 delete = 3 DOM operation, padahal cuma butuh 1 delete. Plus state internal item ke-mix (input value, animation, focus state).

Pakai key={item.id}:

Hasil: 1 delete. Performa optimal + state aman.

Reconciliation Process

React bandingin Virtual DOM lama vs baru:

  1. Bandingkan tipe elemen<div> vs <span> = unmount + mount baru (+ semua child!)
  2. Bandingkan props — className/style berubah = update attribute, tipe sama = reuse
  3. Bandingkan list items by key — match key sama = reuse + update props, mismatched = unmount/mount

State Internal Persist by Key

// Komponen <Counter> punya state internal
function Counter() {
  const [count, setCount] = useState(0)
  return <button onClick={() => setCount(c + 1)}>Count: {count}</button>
}

// User re-order list:
{items.map(item => <Counter key={item.id} />)}  // ✓ count persist per item

{items.map((item, i) => <Counter key={i} />)}  // ✗ pas re-order, count ke-shuffle!

Force Re-mount Pakai Key

Kebalikan: kadang kamu MAU komponen reset (state, animation). Trick: ganti key.

// User pindah ke profile lain → reset semua state internal
<UserProfile key={userId} userId={userId} />

Pas userId berubah, key berubah → React unmount lama + mount baru → state fresh.

🎭 Analogi sehari-hari

key di React itu kayak NIK di KTP. Pas data warga di kelurahan di-update, petugas (React) cek NIK biar tahu siapa yang sama, siapa baru, siapa pindah alamat. Tanpa NIK (atau pake nomor antrian yang berubah-ubah = index), petugas kebingungan: "Si Ani yang ini, sama atau beda dari Si Ani kemarin?". Pakai NIK (id stabil), petugas langsung tahu — efisien + akurat. Reconciliation = proses ulasan yang sama: bandingin "warga lama" (Virtual DOM lama) vs "warga sekarang" (Virtual DOM baru), update kelurahan (real DOM) cuma yang berubah.

⚠️ Jebakan yang sering ditemui

🎯 Pilih key apa?

  • Data dari databaseitem.id ✓ (paling umum, stable)
  • Data dari API tanpa ID stabilitem.uuid atau combine field unik
  • Generated client-sidecrypto.randomUUID() saat dibuat, simpan di state
  • List static yang gak akan berubah urutanindex boleh (cuma kalau YAKIN gak ada add/remove/sort)
  • String content yang unik → string itself (key={item.email})

Aturan: cari nilai STABIL + UNIK per item, gak pernah berubah selama item itu hidup di list.

TL;DR: key = identitas unik per list item, dipake React buat reconciliation (proses diff Virtual DOM). Aturan: unik antar sibling + stabil + jangan random. Index buruk untuk list yang bisa berubah urutan (sort/filter/insert) — state ke-mix. Pakai id dari data. Trick: ganti key untuk force re-mount + reset state. Reconciliation = bandingin tipe element → props → list keys → minimal DOM update.

Yang akan kamu pelajari