State: Array & Object (Immutability)
Memperbarui state yang berupa array atau object tanpa mengubah aslinya.
Aturan emas: jangan ubah state langsung
React mendeteksi perubahan dengan membandingkan referensi. Jika kamu mengubah array/object yang sama, referensinya tidak berubah dan React tidak tahu harus merender ulang:
const [items, setItems] = useState([]);
items.push("baru"); // ❌ mengubah array asli
setItems(items); // referensi sama → tidak ada render ulang
Sebagai gantinya, buat salinan baru dengan nilai yang diperbarui.
Pola untuk array
| Tujuan | Cara (immutable) |
|---|---|
| Tambah | setItems([...items, itemBaru]) |
| Hapus | setItems(items.filter(i => i.id !== id)) |
| Ubah satu | setItems(items.map(i => i.id === id ? { ...i, selesai: true } : i)) |
| Sisip di awal | setItems([itemBaru, ...items]) |
| Urutkan | setItems([...items].sort(...)) |
Hindari method yang mengubah asli: push, pop, splice, sort, reverse (kecuali pada salinan).
Pola untuk object
Gunakan spread untuk menyalin lalu menimpa properti:
const [user, setUser] = useState({ nama: "Dina", umur: 20 });
setUser({ ...user, umur: 21 }); // nama tetap, umur diganti
Untuk object bersarang, salin setiap tingkat yang berubah:
setUser({ ...user, alamat: { ...user.alamat, kota: "Bandung" } });
Contoh: keranjang
function Keranjang() {
const [items, setItems] = useState([]);
function tambah() {
setItems([...items, { id: Date.now(), nama: "Item " + (items.length + 1) }]);
}
function hapus(id) {
setItems(items.filter((i) => i.id !== id));
}
return (
<div>
<button onClick={tambah}>Tambah</button>
<ul>
{items.map((i) => (
<li key={i.id}>{i.nama} <button onClick={() => hapus(i.id)}>x</button></li>
))}
</ul>
</div>
);
}
Kenapa begini?
Immutability membuat perubahan mudah dilacak, mencegah bug yang sulit ditemukan, dan memungkinkan optimasi (React.memo) serta fitur seperti undo. Library seperti Immer mempermudah update bersarang.
Nilai turunan: jangan disimpan di state
Jumlah item cukup items.length — tidak perlu useState terpisah (risiko tidak sinkron).