Pernah pesen kopi di Starbucks? Kamu bilang ke barista: "Latte, ukuran tall, susu oat, no sugar". Barista (komponen) terima list parameter, bikin kopi sesuai pesanan. Customer berikutnya bilang: "Latte, grande, normal milk, extra shot" — barista yang sama, parameter beda, hasil beda. Itu Props di React: data yang dilempar dari komponen parent ke child, bikin komponen reusable bisa berkelakuan beda-beda sesuai parameter yang dikasih.
💡 Aturan emas: props itu READ-ONLY. Komponen child gak boleh ubah props yang dia terima. Mau ubah data? Kasih tau parent (via callback function) biar parent yang ngubah, terus props baru di-pass ulang ke child. Aturan ini bikin data flow predictable — gampang debug "data ini berubah karena siapa".
function Welcome({ name }) {
return <h2>Halo, {name}!</h2>
}
function App() {
return (
<div>
<Welcome name="Andi" />
<Welcome name="Budi" />
<Welcome name="Cici" />
</div>
)
}
Komponen Welcome ditulis sekali. Dipake 3 kali dengan props beda → 3 sapaan beda. Logika reusable, output customizable.
Cara Akses Props
// Cara 1: destructuring di parameter (RECOMMENDED — clean)
function Card({ title, price, image }) {
return <div>{title} - Rp {price}</div>
}
// Cara 2: pakai props object
function Card(props) {
return <div>{props.title} - Rp {props.price}</div>
}
Cara 1 paling sering dipake di codebase modern — langsung kelihatan komponen ini terima props apa aja.
Default Props
function Button({ label, variant = "primary" }) {
return <button className={`btn-${variant}`}>{label}</button>
}
<Button label="Simpan" /> // variant = "primary" (default)
<Button label="Hapus" variant="danger" /> // variant = "danger"
Default value di destructuring kasih fallback kalau prop gak di-pass.
Props Bisa Apa Saja
Bukan cuma string — props bisa nilai apapun: number, boolean, array, object, function, bahkan JSX:
<Card
title="Laptop" // string
price={15000000} // number (pakai {})
inStock={true} // boolean
tags={["elektronik", "promo"]} // array
onBuy={handleBuy} // function (callback)
/>
🎭 Analogi sehari-hari
Props itu kayak isian di formulir KTP. Bentuk formulir (komponen) sama persis untuk semua warga, tapi field-nya (props) beda-beda: nama beda, tanggal lahir beda, alamat beda. Yang ngisi formulir (parent) bisa ngirim 1000 KTP dengan 1000 isian beda — tapi formulir dasarnya tetap satu desain. Plus aturan PENTING: yang nerima formulir (child) gak boleh nambah-nambahin sendiri isiannya — kalau mau ubah, balikin ke yang ngisi (parent), suruh isi ulang dengan data baru.
⚠️ Jebakan yang sering ditemui
- Mutate props langsung —
props.name = "X"atauprops.items.push(...)= MELANGGAR aturan, bug aneh + lint error. Props read-only. Buat data baru atau notify parent. - Lupa
{...}buat non-string —<Card price=15000>(string "15000") vs<Card price={15000}>(number). Beda banget pas dipakai di komputasi. - Pass terlalu banyak props (prop drilling) — komponen di kedalaman 5 level butuh user data, padahal parent terjauh yang punya. Daripada pass props 5 level, pakai Context API (lesson nanti).
- Boolean shorthand —
<Button disabled />= sama dengan<Button disabled={true} />. Pemula kadang nulisdisabled="true"— itu STRING"true"(truthy tapi bukan boolean primitive — bisa bug pasdisabled === true). - Function prop di-recreate tiap render —
<Child onClick={() => doSomething()} />bikin function baru tiap parent re-render. Kalau Child pakaiReact.memo, optimization gak jalan. PakaiuseCallback. - Spread props —
<Card {...userData} />ringkas tapi bisa pass props yang gak diinginkan. Eksplisit lebih aman:<Card name={userData.name} age={userData.age} />.
🎯 Pass data parent → child — pilih cara apa?
- Data sederhana (1-3 props) → langsung pass:
<Card title="X" price={10} />- Banyak props related → object:
<Card user={user} />lalu destructure di child- Children content (JSX) → pakai
children:<Card><h2>Title</h2></Card>- Callback ke parent → function prop:
<Card onDelete={handleDelete} />- Data dalam → 3 level dalam → Context API (jangan prop drilling)
Aturan praktis: explicit > implicit. Pass yang dibutuhkan saja, jangan blindly spread
{...props}.
TL;DR: Props = data dari parent ke child. Read-only — child gak boleh ubah. Akses via destructuring { title, price } (clean). Bisa pass apapun: string, number, boolean, array, object, function, JSX. Wajib {} untuk non-string. Default value: { variant = "primary" }. Mau ubah data? Notify parent via callback function. Prop drilling > 3 level = pakai Context.