Komposisi artinya membangun komponen besar dengan menaruh komponen lain di dalamnya, bukan dengan mewarisi komponen lain. Alatnya ada dua: prop khusus children dan prop biasa yang isinya JSX. Bayangin bingkai foto. Bingkainya memberi pinggiran dan gaya, fotonya bebas kamu selipkan. Satu model bingkai bisa dipakai untuk foto apa pun, dan bingkainya gak perlu tahu foto siapa yang ada di dalamnya. Di React, Card adalah bingkainya, dan children adalah fotonya.
🧪 Tebakan cepat:
Cardmenerimachildren, tapi return-nya cuma<div className="card"></div>. Kalau App menulis<Card><p>Konten kartu</p></Card>, apa yang tampil: paragraf "Konten kartu" atau kotak kosong? Tebak dulu, jawabannya ada di bagian "children: isi di antara tag".
children: isi di antara tag
function Card({ children }) {
return <div className="card">{children}</div>
}
function App() {
return (
<Card>
<p>Konten kartu</p>
</Card>
)
}
Hasilnya di halaman:
<div class="card">
<p>Konten kartu</p>
</div>
- Apa pun yang ditulis di antara
<Card>dan</Card>dikirim React keCardsebagai prop bernamachildren. Kamu gak menulischildren=di mana pun, React yang mengisinya. {children}menaruh isi itu tepat di dalam<div className="card">. Tanpa{children}, isinya gak tampil sama sekali, dan yang keluar cuma kotak kosong. Itu jawaban tebakannya.({ children })mengambilchildrendari props dengan destructuring. Cara lain:function Card(props), lalu{props.children}.Cardyang sama bisa membungkus profil, pengumuman, atau form. Gak perlu bikinProfilCarddanPengumumanCardterpisah.
Slot bernama: prop yang isinya JSX
function Layout({ header, children }) {
return (
<div>
<header className="layout-header">{header}</header>
<main className="layout-content">{children}</main>
</div>
)
}
function App() {
return (
<Layout header={<h1>Selamat Datang</h1>}>
<p>Ini konten utama</p>
</Layout>
)
}
Hasilnya di halaman:
<div>
<header class="layout-header"><h1>Selamat Datang</h1></header>
<main class="layout-content"><p>Ini konten utama</p></main>
</div>
- Prop boleh berisi JSX utuh, bukan cuma teks atau angka.
header={<h1>Selamat Datang</h1>}mengirim satu heading lewat propheader. childrentetap jalan seperti biasa:<p>Ini konten utama</p>ditulis di antara tagLayout.Layoutmenentukan di mana tiap isi ditaruh,Appmenentukan apa isinya. Prop sepertiheadersering disebut slot. Satu komponen boleh punya banyak slot, misalnyaheader,sidebar, danfooter.
Komposisi menggantikan prop drilling
Prop drilling artinya mengoper prop lewat komponen yang gak memakainya, cuma supaya sampai ke komponen di bawahnya. Misalnya foto profil Rina di header:
function Avatar({ user }) {
return <p>{user.nama}</p>
}
// Header gak memakai user, cuma meneruskannya ke Avatar
function Header({ user }) {
return <header className="layout-header"><Avatar user={user} /></header>
}
// Layout juga gak memakai user, cuma meneruskannya ke Header
function Layout({ user, children }) {
return (
<div>
<Header user={user} />
<main className="layout-content">{children}</main>
</div>
)
}
App menulis <Layout user={user}>, dan user turun dua tingkat lewat komponen yang cuma jadi pipa. Dengan slot, App membuat Avatar sendiri lalu menitipkannya ke Layout yang tadi, yang punya slot header:
function App() {
const user = { nama: 'Rina' }
return (
<Layout header={<Avatar user={user} />}>
<Card>
<p>Konten kartu</p>
</Card>
</Layout>
)
}
Sekarang Layout gak tahu apa-apa soal user, dan Header gak dibutuhkan lagi. Kalau Avatar butuh data baru, cuma App dan Avatar yang berubah.
Kenapa React memilih komposisi
Di banyak bahasa, komponen "versi khusus" dibuat dengan inheritance (pewarisan): class SpecialCard extends Card mewarisi semua isi Card lalu menambah sendiri. React menyarankan komposisi, karena lebih fleksibel: pembungkus menerima JSX apa pun lewat children dan slot, dan tiap bagian bisa diganti tanpa mengubah komponen lain. Untuk versi khusus, cukup bungkus:
function Dialog({ title, children }) {
return (
<div className="dialog">
<h2>{title}</h2>
{children}
</div>
)
}
function ConfirmDialog({ children }) {
return <Dialog title="Konfirmasi">{children}</Dialog>
}
ConfirmDialog adalah Dialog yang judulnya sudah diisi. Gak ada extends, cuma membungkus dan meneruskan children.
⚠️ Jebakan yang sering ketemu
- Lupa
{children}.Cardyang me-return<div className="card"><p>Konten kartu</p></div>menulis ulang isinya sendiri dan membuang isi yang dikirim induknya. Taruh{children}langsung di dalam div-nya. - Salah slot.
<header>{children}</header>dan<main>{header}</main>menukar isinya.headermasuk ke<header className="layout-header">,childrenmasuk ke<main className="layout-content">. - Mengirim komponen tanpa tag.
header={Avatar}mengirim function-nya, bukan elemen yang siap tampil. Tulisheader={<Avatar user={user} />}. classdi JSX. Di JSX tulisclassName="card". Di halaman ia jadiclass="card".
TL;DR: Komposisi membangun komponen dengan menaruh komponen lain di dalamnya. children adalah prop khusus berisi apa pun di antara tag pembuka dan penutup, dan komponen pembungkus menaruhnya dengan {children}, misalnya <div className="card">{children}</div>. Untuk lebih dari satu tempat, kirim JSX lewat prop biasa (slot), misalnya <Layout header={<h1>Selamat Datang</h1>}>. Slot juga menghindari prop drilling: komponen di tengah gak perlu meneruskan data yang gak mereka pakai. React memilih komposisi daripada inheritance karena lebih fleksibel.