Higher-Order Component (HOC) adalah function yang menerima sebuah komponen, lalu mengembalikan komponen baru yang membungkusnya dengan sesuatu tambahan: kerangka, pengecekan, atau props ekstra. Komponen aslinya gak diubah sama sekali. Mirip tukang bingkai foto: kamu serahkan foto apa pun, dia kembalikan foto yang sudah berbingkai. Foto aslimu tetap ada tanpa bingkai, dan bingkai yang sama bisa dipakai untuk foto lain.
🧪 Tebakan cepat: sesudah
const GreetingWithWrapper = withWrapper(Greeting), kamu tetap merender<Greeting nama="Budi" />yang biasa. Apakah sapaannya sekarang ikut terbungkus<div id="wrapper">? Tebak dulu, jawabannya ada di bagian "Function yang menerima komponen".
Function yang menerima komponen
Mulai dari komponen biasa yang menyapa lewat prop nama:
function Greeting({ nama }) {
return <p id="greeting">Halo, {nama}!</p>
}
HOC-nya, withWrapper, menaruh sapaan itu di dalam sebuah kerangka:
function withWrapper(Component) {
return function WithWrapper(props) {
return (
<div id="wrapper">
<Component {...props} />
</div>
)
}
}
// dipanggil sekali, di luar komponen mana pun
const GreetingWithWrapper = withWrapper(Greeting)
function App() {
return <GreetingWithWrapper nama="Budi" />
}
withWrapper(Component)adalah function biasa. Parameternya sebuah komponen, biasanya dinamaiComponentatauWrappedComponent.return function WithWrapper(props) {...}: yang dikembalikan adalah komponen baru.withWrappersendiri gak merender apa-apa, dia cuma membuat komponen.<Component {...props} />merender komponen asli di dalam div.{...props}meneruskan semua props yang diterima pembungkus, jadinamasampai keGreeting.- Hasil HOC disimpan di
GreetingWithWrapperdan dipakai seperti komponen lain:<GreetingWithWrapper nama="Budi" />.
Greeting sendiri gak berubah. <Greeting nama="Budi" /> tetap merender <p> saja, tanpa div. Yang terbungkus cuma komponen baru, GreetingWithWrapper. Itu jawaban tebakannya.
Jalannya props, dari App sampai layar
| Langkah | Komponen | Props yang diterima | Yang dirender |
|---|---|---|---|
| 1 | App |
(gak ada) | <GreetingWithWrapper nama="Budi" /> |
| 2 | WithWrapper |
{ nama: "Budi" } |
<div id="wrapper"> berisi <Greeting {...props} /> |
| 3 | Greeting |
{ nama: "Budi" } |
<p id="greeting">Halo, Budi!</p> |
Hasil akhirnya di halaman:
<div id="wrapper">
<p id="greeting">Halo, Budi!</p>
</div>
Pohon komponennya jadi dua lapis: WithWrapper di luar, Greeting di dalam. Kalau langkah 2 menulis <Component /> tanpa {...props}, Greeting menerima {} dan sapaannya jadi Halo, !.
HOC yang menambah logika
HOC gak cuma menambah kerangka. withLoading memutuskan apakah komponen aslinya boleh dirender:
function withLoading(Component) {
return function WithLoading({ isLoading, ...props }) {
if (isLoading) {
return <p>Loading...</p>
}
return <Component {...props} />
}
}
const EnhancedGreeting = withLoading(withWrapper(Greeting))
// <EnhancedGreeting nama="Budi" isLoading={true} /> tampil: Loading...
// <EnhancedGreeting nama="Budi" isLoading={false} /> tampil: Halo, Budi! di dalam div#wrapper
{ isLoading, ...props }mengambilisLoading, lalu sisanya (nama) dikumpulkan diprops. JadiisLoadingberhenti di lapis ini dan gak ikut turun.- Kalau
isLoadingtrue,WithLoadinglangsung mengembalikan<p>Loading...</p>.WithWrapperdanGreetinggak dirender sama sekali. - HOC bisa ditumpuk.
withLoading(withWrapper(Greeting))membuat tiga lapis, dan HOC yang paling kiri jadi lapis paling luar.
Aturan menulis HOC
- Nama diawali
with:withWrapper,withLoading,withAuth. Dari namanya orang langsung tahu function itu membungkus komponen. - Teruskan props:
<Component {...props} />, supaya komponen asli tetap menerima semua yang dikirim ke pembungkusnya. - Jangan ubah komponen asli. Kembalikan komponen baru, jangan menempelkan sesuatu ke
Greeting. - Panggil HOC sekali, di luar komponen, lalu simpan hasilnya di konstanta.
Kenapa sekarang jarang dipakai: custom hook
HOC populer sebelum hooks ada (sebelum React 16.8, tahun 2019). Sekarang, kalau yang mau dipakai ulang adalah logika (state, effect), caranya custom hook: function berawalan use yang dipanggil langsung di dalam komponen. Kamu akan membuatnya dua pelajaran lagi. Bandingkan bentuknya:
// HOC: data user disuntikkan sebagai prop, lewat satu lapis komponen tambahan
const ProfileWithUser = withUser(Profile)
// Custom hook: dipanggil langsung di komponen, gak ada lapis tambahan
function Profile() {
const user = useUser()
return <p>Halo, {user.nama}!</p>
}
- Tiap HOC menambah satu lapis di pohon komponen. Tiga HOC ditumpuk berarti tiga pembungkus yang harus ditelusuri waktu ada bug.
- Prop dari HOC muncul begitu saja di komponen asli. Dengan hook, asal datanya tertulis di baris yang memakainya.
- HOC tetap kamu temui di kode lama dan beberapa library:
connect(...)(Komponen)dari Redux versi lama,withRouterdari React Router v5.memo(Komponen)yang nanti kamu pelajari juga bentuknya sama: menerima komponen, mengembalikan komponen baru.
⚠️ Jebakan yang sering ketemu
- Lupa
{...props}.<Component />tanpa props bikinGreetingmenerima{}, jadi sapaannyaHalo, !. - Memanggil HOC di dalam render.
const GreetingWithWrapper = withWrapper(Greeting)di dalamAppmembuat komponen baru tiap kali App render. React menganggapnya komponen yang berbeda, jadi isinya dibuang dan dibuat ulang, dan state di dalamnya hilang. - Mengetik sapaannya utuh.
<p id="greeting">Halo, Budi!</p>memang tampil benar, tapi gak memakai prop. Rakit dari prop:Halo, {nama}!. - Menumpuk terlalu banyak.
withA(withB(withC(withD(Page))))berarti empat lapis pembungkus. Kalau yang dibagi cuma logika, pakai custom hook.
TL;DR: HOC adalah function yang menerima komponen dan mengembalikan komponen baru yang membungkusnya. Namanya diawali with, parameternya biasa dinamai Component, dan komponen baru itu merender <Component {...props} /> supaya semua props tetap sampai. Komponen asli gak berubah. Panggil HOC sekali di luar komponen: const GreetingWithWrapper = withWrapper(Greeting). HOC bisa menambah kerangka (withWrapper) atau logika (withLoading), dan bisa ditumpuk, tiap HOC satu lapis. Di kode baru, logika yang dipakai ulang biasanya ditulis sebagai custom hook; HOC masih kamu temui di kode dan library lama.