Prop drilling adalah mengirim prop melewati komponen yang tidak memakainya, hanya agar komponen yang lebih jauh di bawah tree bisa memakainya. Di sini, user berpindah dari App melewati Page dan Sidebar untuk mencapai Avatar, satu-satunya komponen yang membacanya.
Empat level, dan hanya level terakhir yang peduli pada user. Konsol menunjukkan Page dan Sidebar berjalan untuk sebuah nilai yang tidak pernah mereka tampilkan. Klik tombolnya, dan keduanya mencatat log lagi.
Kenapa ini merepotkan
Dua atau tiga level itu wajar. Prop drilling menjadi masalah saat tree bertambah besar:
- Komponen di tengah membawa props yang tidak dipakainya.
PagedanSidebarsekarang punya propuserdi signature-nya, jadi kamu tidak bisa membacanya tanpa bertanya-tanya untuk apa prop itu. - Setiap perubahan menyentuh setiap lapisan. Tambahkan
user.avatarUrlatau nilai kedua sepertionLogout, dan kamu mengedit setiap komponen di sepanjang jalurnya, bukan hanya kedua ujungnya. - Memindahkan komponen memutus rantainya. Pindahkan
Avatarke cabang lain, dan kamu harus menyalurkanuserlewat jalur baru. - Prop mudah terlewat. Lupa meneruskannya di satu lapisan, dan komponen di bawah mendapat
undefined, tanpa error di lapisan yang kehilangannya.
Coba sendiri: tambahkan fungsi onLogout di App yang harus dipanggil Avatar. Kamu akan mengedit keempat komponen.
Solusi 1: komposisi dengan children
Solusi inilah yang sering dilewatkan orang. Alih-alih mengirim data ke bawah agar komponen di dalam bisa merender dengannya, biarkan komponen pemilik data merender sendiri komponen di dalam itu, lalu kirim elemen jadinya ke bawah sebagai children (atau prop lain). Lapisan tengah merender sebuah slot dan tidak pernah melihat user.
Page dan Sidebar tidak lagi tahu bahwa ada user. App membuat Avatar di tempat user berada dan menyerahkannya ke bawah sebagai elemen jadi. Komponen layout seperti ini menjadi bisa dipakai ulang, dan menambahkan onLogout sekarang hanya mengubah App dan Avatar. Keduanya tetap mencatat log di setiap klik, karena App mengirim elemen baru setiap kali ia merender: komposisi menyederhanakan kode, bukan jumlah render. Halaman children membahas lebih banyak pola slot.
Komposisi berhasil saat komponen pemilik data juga bisa menentukan tampilan bagian di dalam. Cara ini tidak membantu saat komponen di dalam itu berada di dalam library atau struktur yang tidak dirender oleh pemiliknya.
Solusi 2: context
Saat banyak komponen di kedalaman yang berbeda butuh nilai yang sama (tema, user yang sedang login, bahasa saat ini), taruh nilai itu di context. Komponen mana pun di bawah provider membacanya dengan useContext, dan tidak ada yang berubah di antaranya.
Avatar dan Greeting membaca user dari dua kedalaman yang berbeda, dan Page serta Sidebar tidak menerima props. Tambahkan pembaca ketiga di mana saja di bawah Page, dan ia langsung berfungsi tanpa menyentuh yang lain. Biayanya: alur data tidak lagi terlihat di props, dan setiap pembaca merender saat nilainya berubah. Halaman useContext membahas provider, nilai default, dan render ulang tersebut.
Solusi 3: library state
Untuk state aplikasi yang besar, dibaca banyak komponen, dan sering berubah (keranjang belanja, editor dokumen, data live), library state seperti Redux Toolkit, Zustand, atau Jotai memungkinkan setiap komponen subscribe hanya ke bagian yang dipakainya. Cara ini menghindari drilling sekaligus biaya "setiap konsumen ikut merender" dari satu context besar. Ini juga berarti satu dependensi tambahan dan sekumpulan konsep baru, jadi pakai saat dua solusi pertama tidak lagi cukup, bukan untuk memperbaiki prop yang berpindah tiga level.
// Zustand, for comparison (not available in the editor here)
const useCart = create((set) => ({
items: [],
add: (item) => set((s) => ({ items: [...s.items, item] })),
}));
function CartCount() {
const count = useCart((s) => s.items.length); // renders only when the count changes
return <span>{count}</span>;
}
Kapan prop drilling tidak masalah
Mengirim props adalah cara data mengalir di React, dan merupakan pola yang paling mudah dibaca: kamu bisa mengikuti sebuah nilai dari atas sampai bawah hanya dengan melihat JSX-nya. Prop yang melewati satu atau dua komponen yang memakai sebagiannya, atau melewati rantai pendek komponen yang saling berkaitan erat, bukan masalah yang perlu dipecahkan. Angkat state ke induk bersama terdekat, kirim ke bawah, dan baru ganti pendekatan saat lapisan tengah mulai membawa props yang tidak ada gunanya bagi mereka.
Pertanyaan yang sering diajukan
Apa itu prop drilling di React?
Prop drilling adalah mengirim prop ke bawah melewati beberapa lapisan komponen yang tidak memakainya, hanya agar komponen yang berada jauh di dalam tree bisa membacanya. Setiap komponen di tengah menerima prop itu lalu meneruskannya.
Apakah prop drilling itu buruk?
Tidak dengan sendirinya. Mengirim nilai dua atau tiga level ke bawah itu eksplisit dan mudah diikuti. Ini baru menjadi masalah saat banyak lapisan membawa props yang tidak pernah dipakainya, sehingga setiap penggantian nama atau field baru menyentuh file yang tidak ada hubungannya.
Bagaimana cara menghindari prop drilling?
Coba komposisi dulu: biarkan induk membuat komponen yang berada jauh di dalam lalu mengirimnya ke bawah sebagai children atau prop lain, sehingga lapisan tengah tidak pernah melihat datanya. Jika banyak komponen di kedalaman berbeda butuh nilai itu, pakai context. Untuk state besar yang sering berubah, pertimbangkan library state.
Apakah context satu-satunya solusi prop drilling?
Bukan, dan sering kali bukan yang terbaik. Komposisi dengan children menghilangkan drilling tanpa menambah context, dan alur datanya tetap terlihat di kode.