Setelah menyiapkan project React di artikel sebelumnya, saatnya memahami konsep paling fundamental React: komponen dan props. Komponen adalah blok bangunan UI — bayangkan seperti Lego, di mana setiap bagian interface (tombol, kartu, navigasi) adalah komponen yang bisa digunakan berulang kali. Props adalah cara meneruskan data ke komponen, seperti parameter fungsi.
Function Component Dasar
Di React modern, komponen adalah fungsi JavaScript yang mengembalikan JSX:
// Komponen sederhana — nama harus dimulai huruf kapital!
function Salam() {
return <h1>Selamat datang di KamusNgoding! 👋</h1>;
}
// Penggunaan di App.jsx
function App() {
return (
<div>
<Salam />
<Salam /> {/* Bisa digunakan berkali-kali */}
</div>
);
}
Aturan penting: Nama komponen harus dimulai huruf kapital.
<salam />akan dianggap HTML tag, bukan komponen React.<Salam />adalah komponen React.
Props — Meneruskan Data ke Komponen
// Komponen dengan props
function KartuPengguna(props) {
return (
<div style={{ border: "1px solid #ccc", padding: "16px", borderRadius: "8px" }}>
<h3>{props.nama}</h3>
<p>Email: {props.email}</p>
<p>Jabatan: {props.jabatan}</p>
</div>
);
}
// Penggunaan — kirim data melalui atribut JSX
function App() {
return (
<div>
<KartuPengguna
nama="Ali Akbar"
email="[email protected]"
jabatan="Frontend Developer"
/>
<KartuPengguna
nama="Budi Santoso"
email="[email protected]"
jabatan="Backend Developer"
/>
</div>
);
}
Destructuring Props — Cara yang Lebih Bersih
// Destructuring langsung di parameter fungsi
function KartuProduk({ nama, harga, stok, kategori }) {
return (
<div className="kartu-produk">
<h3>{nama}</h3>
<p>Kategori: {kategori}</p>
<p>Harga: Rp {harga.toLocaleString("id-ID")}</p>
<p>Stok: {stok} unit</p>
</div>
);
}
// Penggunaan
<KartuProduk
nama="Laptop ThinkPad"
harga={15000000}
stok={5}
kategori="Elektronik"
/>
Props children — Konten di Dalam Komponen
// children adalah konten yang ditulis di antara tag buka dan tutup
function Kartu({ judul, children }) {
return (
<div style={{ border: "1px solid var(--color-border)", padding: "20px" }}>
<h2 style={{ color: "var(--color-primary)" }}>{judul}</h2>
<div>{children}</div>
</div>
);
}
// Penggunaan
function App() {
return (
<Kartu judul="Informasi Akun">
<p>Username: ali_akbar</p>
<p>Level: Premium</p>
<button>Edit Profil</button>
</Kartu>
);
}
Default Props
function Badge({ teks, warna = "#00FF88", ukuran = "small" }) {
const style = {
backgroundColor: warna,
padding: ukuran === "small" ? "4px 8px" : "8px 16px",
borderRadius: "4px",
fontSize: ukuran === "small" ? "12px" : "16px",
};
return <span style={style}>{teks}</span>;
}
// Penggunaan
<Badge teks="Pemula" /> {/* Menggunakan default */}
<Badge teks="Mahir" warna="#FF6B6B" ukuran="large" />
Conditional Rendering
Menggunakan && (Render jika true)
function StatusPengguna({ isLogin, nama }) {
return (
<div>
{isLogin && <p>Halo, {nama}! Kamu sudah login.</p>}
{!isLogin && <p>Silakan login untuk melanjutkan.</p>}
</div>
);
}
Menggunakan Ternary ? :
function TombolStok({ tersedia }) {
return (
<button
disabled={!tersedia}
style={{ backgroundColor: tersedia ? "#00FF88" : "#8B949E" }}
>
{tersedia ? "Tambah ke Keranjang" : "Stok Habis"}
</button>
);
}
Menggunakan if dalam JSX (untuk kondisi kompleks)
function StatusPesanan({ status }) {
let konten;
let warna;
if (status === "menunggu") {
konten = "⏳ Menunggu konfirmasi";
warna = "#F0E05A";
} else if (status === "dikirim") {
konten = "🚚 Sedang dikirim";
warna = "#818CF8";
} else if (status === "selesai") {
konten = "✅ Pesanan selesai";
warna = "#00FF88";
} else {
konten = "❌ Pesanan dibatalkan";
warna = "#FF6B6B";
}
return (
<span style={{ color: warna, fontWeight: "bold" }}>
{konten}
</span>
);
}
Rendering List dengan map()
function DaftarProduk({ produk }) {
return (
<ul>
{produk.map((item) => (
// key WAJIB ada! Gunakan ID unik, bukan indeks array jika bisa
<li key={item.id}>
<strong>{item.nama}</strong> — Rp {item.harga.toLocaleString("id-ID")}
</li>
))}
</ul>
);
}
// Penggunaan
const daftar_produk = [
{ id: 1, nama: "Laptop", harga: 15000000 },
{ id: 2, nama: "Mouse", harga: 250000 },
{ id: 3, nama: "Keyboard", harga: 750000 },
];
<DaftarProduk produk={daftar_produk} />
Mengapa
keypenting? React menggunakankeyuntuk melacak elemen mana yang berubah saat list diperbarui. Tanpa key yang unik, React mungkin salah mengidentifikasi elemen dan menyebabkan bug yang susah dilacak.
Memecah Komponen — Component Composition
// Setiap komponen punya satu tanggung jawab
function Avatar({ src, nama }) {
return (
<img
src={src}
alt={nama}
style={{ width: 40, height: 40, borderRadius: "50%" }}
/>
);
}
function InfoPengguna({ nama, peran }) {
return (
<div>
<strong>{nama}</strong>
<small style={{ color: "var(--color-text-muted)", display: "block" }}>
{peran}
</small>
</div>
);
}
// Komponen yang lebih besar menggunakan komponen lebih kecil
function HeaderPengguna({ pengguna }) {
return (
<div style={{ display: "flex", alignItems: "center", gap: "12px" }}>
<Avatar src={pengguna.avatarUrl} nama={pengguna.nama} />
<InfoPengguna nama={pengguna.nama} peran={pengguna.peran} />
</div>
);
}
// Penggunaan
const pengguna = {
nama: "Ali Akbar",
peran: "Frontend Developer",
avatarUrl: "/images/ali.jpg"
};
<HeaderPengguna pengguna={pengguna} />
Troubleshooting: Error yang Sering Muncul
Warning: Each child in a list should have a unique "key" prop
Penyebab: Saat merender list dengan map(), setiap elemen harus memiliki prop key yang unik agar React bisa melacak perubahan dengan efisien.
Solusi:
// Salah — tanpa key
{produk.map(item => (
<KartuProduk nama={item.nama} />
))}
// Benar — gunakan id unik dari data
{produk.map(item => (
<KartuProduk key={item.id} nama={item.nama} />
))}
// Hindari index sebagai key (kecuali list statis yang tidak berubah urutan)
{produk.map((item, index) => (
<KartuProduk key={index} nama={item.nama} />
))}
Cannot read properties of undefined (reading 'map')
Penyebab: Props yang diharapkan berupa array ternyata undefined — biasanya karena data belum dimuat atau lupa meneruskan props ke komponen.
Solusi:
// Crash jika `items` undefined
function Daftar({ items }) {
return items.map(item => <li>{item}</li>);
}
// Berikan default value di parameter
function Daftar({ items = [] }) {
return items.map(item => <li key={item.id}>{item.nama}</li>);
}
// Atau gunakan optional chaining
{items?.map(item => <li key={item.id}>{item.nama}</li>)}
JSX merender angka 0 yang tidak diinginkan
Penyebab: Menggunakan && dengan nilai falsy selain false dan null — nilai 0 akan ikut dirender sebagai teks di layar.
Solusi:
// Merender angka "0" ke layar jika jumlah === 0
{jumlah && <Badge count={jumlah} />}
// Konversi eksplisit ke boolean
{jumlah > 0 && <Badge count={jumlah} />}
Pertanyaan yang Sering Diajukan
Mengapa harus ada satu root element di JSX?
JSX dikompilasi menjadi React.createElement() yang hanya bisa mengembalikan satu nilai. Jika ingin mengembalikan beberapa elemen tanpa wrapper div, gunakan Fragment: <>...</> atau <React.Fragment>...</React.Fragment>. Fragment tidak menghasilkan elemen DOM tambahan.
Apakah props bisa berupa fungsi?
Ya! Props bisa berisi nilai apapun yang valid di JavaScript: string, number, boolean, array, objek, bahkan fungsi. Meneruskan fungsi sebagai props adalah cara utama untuk komunikasi dari child ke parent component — ini yang disebut “callback props” dan akan dipelajari lebih dalam di artikel event handling.
Mengapa menggunakan index array sebagai key tidak disarankan?
Jika kamu menggunakan indeks array sebagai key dan urutan list berubah (karena insert, delete, atau sort), React akan memiliki referensi key yang tidak akurat. Ini bisa menyebabkan bug subtle seperti form yang tidak direset atau animasi yang salah. Gunakan ID unik dari data jika tersedia.
Berapa banyak komponen yang ideal dalam satu file?
Tidak ada aturan ketat, tapi konvensi umum: satu komponen besar per file, tapi komponen kecil terkait boleh di file yang sama. Jika komponen mulai terasa terlalu besar (lebih dari ~150 baris), pertimbangkan untuk memecahnya. Prinsipnya: setiap komponen punya satu tanggung jawab yang jelas.
Kesimpulan
| Konsep | Cara Penggunaan |
|---|---|
| Function component | function Nama({ props }) { return <jsx/> } |
| Props | Atribut di JSX: <Comp nama="nilai" /> |
| Destructuring | function Comp({ nama, umur }) { ... } |
| Children | function Comp({ children }) { return <div>{children}</div> } |
| Default value | function Comp({ warna = "merah" }) { ... } |
Conditional (&&) | {kondisi && <Elemen />} |
| Conditional (ternary) | {kondisi ? <A /> : <B />} |
| List rendering | {items.map(item => <Li key={item.id} />)} |
Artikel sebelumnya: Mulai Cepat dengan React — setup project React dengan Vite.
Langkah selanjutnya: State dan Hooks di React — cara membuat UI yang interaktif dengan useState dan useEffect.