Di banyak bahasa OOP (Java, C#), pattern "extends" populer — ClassA extends ClassB, dapat semua method ClassB plus tambah sendiri. React MENOLAK pattern ini. Sebagai gantinya: komposisi — gabungin komponen kecil jadi yang besar via children/slots, bukan inherit. Kenapa? Komposisi lebih fleksibel, lebih mudah di-test, dan match natural dengan UI nesting (HTML aslinya tree of elements).
💡 "Composition over inheritance" — prinsip software design yang udah berusia 30+ tahun, jadi salah satu fondasi React. Tim React tegas: gak ada
class extends Componentstyle inheritance. Mau reuse? Pecah jadi komponen kecil + komposisi. Mau share logic? Custom hooks (lesson nanti). Mau preset? Specialization via wrap.
Children Prop — Slot Universal
function Card({ children }) {
return <div className="card">{children}</div>
}
function App() {
return (
<Card>
<h2>Judul</h2>
<p>Isi kartu</p>
<button>Aksi</button>
</Card>
)
}
children = prop spesial yang berisi apapun yang ditempatkan di antara tag pembuka dan penutup. Card jadi "wadah" yang fleksibel — bisa diisi h2, p, button, bahkan komponen lain.
Multiple Slots — Pakai Props
function SplitPane({ left, right }) {
return (
<div className="split">
<div className="left">{left}</div>
<div className="right">{right}</div>
</div>
)
}
function App() {
return (
<SplitPane
left={<Sidebar />}
right={<MainContent />}
/>
)
}
Pass JSX as props = "named slots". Pattern ini powerful banget buat layout component.
Specialization — Wrap untuk Preset
function Dialog({ title, children }) {
return (
<div className="dialog">
<h2>{title}</h2>
<div>{children}</div>
</div>
)
}
// Specialization: Dialog dengan preset "Konfirmasi"
function ConfirmDialog({ children }) {
return (
<Dialog title="Konfirmasi">
{children}
</Dialog>
)
}
// Pemakaian
<ConfirmDialog>
<p>Yakin ingin menghapus?</p>
<button>Ya</button>
</ConfirmDialog>
Containment vs Specialization
| Pattern | Use Case |
|---|---|
| Containment (children prop) | Komponen "wadah" yang isinya bebas: <Card>, <Modal>, <Layout> |
| Specialization (wrap dengan preset) | Komponen "varian" dari yang lebih umum: <ConfirmDialog> extend <Dialog> |
🎭 Analogi sehari-hari
Komposisi React kayak bumbu kering instan + bumbu basah racikan sendiri. Bumbu kering instan = komponen base (<Card>, <Button>, <Dialog>) — udah tersedia, fungsional. Tinggal masuk bahan racik (children, props spesifik) sesuai resep masakan akhir kamu. Mau bikin nasi goreng pedas? Bumbu instan + cabe ekstra. Mau bikin variasi rendang? Bumbu instan + kelapa parut. Inheritance kayak harus modifikasi resep instan-nya — ngerubah pabriknya. Komposisi = pakai produk apa adanya, racik di rumah. Lebih fleksibel, gak ngerusak yang udah jadi.
⚠️ Jebakan yang sering ditemui
- Render props ribet —
<Card render={() => <p>...</p>} />lebih lama dipake, sekarang prefer children prop. - Mau extend komponen via inheritance —
class CardSpecial extends Card {}= anti-pattern di React. Pakai composition:<Card><Special /></Card>. - Children "ngebol" ke deep nested — pass children dari atas, render di bawah dalam. OK, but pertimbangkan kalau jadi prop drilling.
- Conditional children —
{condition && children}OK.{children && condition}evaluate dulu children sebagai boolean — bug. - Children sebagai function (render prop) —
<List>{(item) => <Item />}</List>— work, tapi prefer patternrenderItemprop atau just pass component. - Spread
{...props}di children — clobber children, bug aneh. Eksplisit children pass.
🎯 Pilih strategy reuse — pakai apa?
- Komponen "wadah" UI yang isinya bebas → children prop (
<Card>,<Modal>)- Komponen layout dengan banyak slot → props sebagai slots (
<SplitPane left={X} right={Y}>)- Variasi dari komponen umum → specialization via wrap (
<ConfirmDialog>wrap<Dialog>)- Reuse LOGIC tanpa UI → custom hook (
useToggle,useFetch)- Mau "extend" component dari library → wrap via composition, bukan inherit
- Cross-cutting concern (logging, auth) → HOC atau wrapper component
Anti-pattern absolute:
class MyComponent extends OtherComponent— JANGAN pernah. React way = composition.
TL;DR: Komposisi = bangun komponen kompleks dari komponen sederhana via slots. children prop = slot universal (apapun di antara tag). Multiple slots = pass JSX as props. Specialization = wrap dengan preset. React rejects inheritance — pakai composition. Reuse LOGIC pakai custom hooks. Anti-pattern: class X extends Y — never do it.