Komposisi Komponen — React

Di banyak bahasa OOP (Java, C#), pattern "extends" populer — ClassA extends ClassB, dapat semua method ClassB plus tambah sendiri. React MENOLAK pattern ini. Se

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 Component style 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

🎯 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.

Yang akan kamu pelajari