Bab 1: Komponen Pertamamu

3 menit baca

Apa Itu Component?

Kamu pasti pernah main puzzle. Setiap keping puzzle punya bentuk unik, tapi kalau digabung jadi gambar utuh. Component di React itu keping puzzle — setiap component punya tampilan dan fungsi sendiri, tapi kalau dirakit jadi website utuh.

Secara teknis, component adalah fungsi JavaScript yang mengembalikan markup (JSX). Itu aja. Sesimpel itu.

jsx
function Tombol() {
  return <button>Klik Saya</button>;
}

Coba sendiri: Edit kode di bawah dan lihat hasilnya langsung!

Boom — itu udah component. Namanya Tombol, tugasnya menampilkan satu tombol.


Kenapa Pakai Component?

Tanpa Component (HTML biasa):

html
<!-- Navbar di halaman 1 -->
<nav><a href="/">Home</a><a href="/about">About</a></nav>

<!-- Navbar di halaman 2 (copy-paste) -->
<nav><a href="/">Home</a><a href="/about">About</a></nav>

<!-- Navbar di halaman 3 (copy-paste lagi) -->
<nav><a href="/">Home</a><a href="/about">About</a></nav>

Mau ubah satu link? Harus edit di semua halaman. 😱

Dengan Component:

jsx
function Navbar() {
  return <nav><a href="/">Home</a><a href="/about">About</a></nav>;
}

// Pakai di mana aja:
<Navbar />
<Navbar />
<Navbar />

Mau ubah? Edit sekali di component, otomatis berubah di semua tempat. ✨


Cara Membuat Component

Langkah 1: Buat Fungsi

jsx
function Profil() {
  // ...
}

Langkah 2: Return JSX

jsx
function Profil() {
  return (
    <img
      src="https://example.com/foto.jpg"
      alt="Foto profil"
    />
  );
}

Langkah 3: Export

jsx
export default function Profil() {
  return (
    <img
      src="https://example.com/foto.jpg"
      alt="Foto profil"
    />
  );
}

export default artinya: "Ini component utama di file ini, bisa di-import file lain."


Aturan Penamaan Component

WAJIB: Huruf Kapital di Awal

jsx
// ✅ BENAR
function KartuProduk() { ... }
function NavbarUtama() { ... }
function TombolBeli() { ... }

// ❌ SALAH — React anggap ini HTML tag
function kartuProduk() { ... }
function navbar() { ... }

Kenapa?

React membedakan component vs HTML tag berdasarkan huruf pertama:

  • <div> → huruf kecil → HTML tag
  • <Navbar> → huruf besar → Component buatan kamu

Kalau kamu tulis <navbar>, React cari tag HTML bernama "navbar" — yang nggak ada. Error.

Konvensi Penamaan

  • PascalCase untuk component: KartuProduk, DaftarKontak, FormLogin
  • camelCase untuk variabel/fungsi biasa: handleKlik, jumlahItem, isLoading

Menyusun Component (Nesting)

Component bisa dipanggil di dalam component lain. Ini namanya composition — kekuatan utama React.

jsx
function Avatar() {
  return <img src="foto.jpg" alt="avatar" style={{ borderRadius: "50%" }} />;
}

function KartuUser() {
  return (
    <div style={{ border: "1px solid #ccc", padding: "16px" }}>
      <Avatar />
      <h2>Yazid Akbar</h2>
      <p>Web Developer</p>
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>Tim Kami</h1>
      <KartuUser />
      <KartuUser />
      <KartuUser />
    </div>
  );
}

Hierarki Component

App (parent) └── KartuUser (child dari App) └── Avatar (child dari KartuUser)
  • App = parent dari KartuUser
  • KartuUser = child dari App, parent dari Avatar
  • Avatar = child dari KartuUser
💡Info

Boneka besar berisi boneka lebih kecil, yang berisi boneka lebih kecil lagi. Setiap boneka "lengkap" sendiri, tapi bisa ditaruh di dalam boneka lain.


Satu File vs Banyak File

Satu File (untuk component kecil yang terkait):

jsx
// components/Galeri.jsx
function Foto({ src, alt }) {
  return <img src={src} alt={alt} style={{ width: "200px" }} />;
}

export default function Galeri() {
  return (
    <div>
      <Foto src="1.jpg" alt="Foto 1" />
      <Foto src="2.jpg" alt="Foto 2" />
      <Foto src="3.jpg" alt="Foto 3" />
    </div>
  );
}

Foto nggak di-export karena cuma dipakai di file ini. Galeri di-export karena dipakai file lain.

Banyak File (untuk component yang di-reuse di banyak tempat):

src/ ├── components/ │ ├── Navbar.jsx │ ├── Footer.jsx │ ├── Tombol.jsx │ └── KartuProduk.jsx ├── App.jsx └── main.jsx

Kapan pisah file?

  • Component dipakai di lebih dari 1 tempat → pisah
  • Component sudah lebih dari 50 baris → pertimbangkan pisah
  • Component punya logika kompleks sendiri → pisah

⚠️ Jebakan

1. Definisi Component di Dalam Component

jsx
// ❌ SALAH — JANGAN definisikan component di dalam component lain!
function Galeri() {
  function Foto() {  // Ini akan dibuat ulang setiap render!
    return <img src="foto.jpg" />;
  }

  return <Foto />;
}

// ✅ BENAR — definisikan di level teratas
function Foto() {
  return <img src="foto.jpg" />;
}

function Galeri() {
  return <Foto />;
}

Kenapa salah? Kalau Foto didefinisikan di dalam Galeri, setiap kali Galeri re-render, React bikin Foto baru dari nol. Ini bikin:

  • Performa lambat
  • State di Foto hilang setiap render
  • Bug yang susah dilacak

2. Lupa Return

jsx
// ❌ Nggak return apa-apa — component kosong
function Judul() {
  <h1>Halo</h1>;  // Lupa return!
}

// ✅ Benar
function Judul() {
  return <h1>Halo</h1>;
}

3. Return Multi-line Tanpa Kurung

jsx
// ❌ Error — JavaScript anggap return selesai di baris itu
function Kartu() {
  return
    <div>
      <h1>Judul</h1>
    </div>;
}

// ✅ Benar — bungkus dengan kurung ()
function Kartu() {
  return (
    <div>
      <h1>Judul</h1>
    </div>
  );
}

Ini karena JavaScript punya fitur "Automatic Semicolon Insertion" — dia otomatis taruh ; setelah return kalau baris berikutnya kosong.


Contoh Penggunaan Nyata

Component Navbar

jsx
function NavLink({ href, children }) {
  return (
    <a href={href} style={{ marginRight: "16px", textDecoration: "none" }}>
      {children}
    </a>
  );
}

function Navbar() {
  return (
    <nav style={{ background: "#333", padding: "12px" }}>
      <NavLink href="/">Home</NavLink>
      <NavLink href="/produk">Produk</NavLink>
      <NavLink href="/tentang">Tentang</NavLink>
      <NavLink href="/kontak">Kontak</NavLink>
    </nav>
  );
}

Component Card Testimonial

jsx
function Bintang({ jumlah }) {
  return <span>{"⭐".repeat(jumlah)}</span>;
}

function Testimonial({ nama, teks, rating }) {
  return (
    <div style={{ border: "1px solid #eee", padding: "16px", borderRadius: "8px", marginBottom: "12px" }}>
      <Bintang jumlah={rating} />
      <p style={{ fontStyle: "italic" }}>"{teks}"</p>
      <p style={{ fontWeight: "bold" }}>— {nama}</p>
    </div>
  );
}

function HalamanTestimonial() {
  return (
    <div>
      <h2>Apa Kata Mereka</h2>
      <Testimonial nama="Budi" teks="Produknya bagus banget!" rating={5} />
      <Testimonial nama="Ani" teks="Pengiriman cepat, recommended!" rating={4} />
      <Testimonial nama="Citra" teks="Harga terjangkau, kualitas oke." rating={4} />
    </div>
  );
}

🏋️ Challenge

Challenge 1: Galeri Foto

Buat component Galeri yang menampilkan 4 foto ilmuwan. Buat component Foto terpisah yang menerima props nama dan src.

💡 Hint
jsx
function Foto({ nama, src }) {
  return (
    <figure>
      <img src={src} alt={nama} />
      <figcaption>{nama}</figcaption>
    </figure>
  );
}
✅ Solusi
jsx
function Foto({ nama, src }) {
  return (
    <figure style={{ display: "inline-block", margin: "10px", textAlign: "center" }}>
      <img src={src} alt={nama} style={{ width: "150px", height: "150px", borderRadius: "8px" }} />
      <figcaption>{nama}</figcaption>
    </figure>
  );
}

export default function Galeri() {
  return (
    <div>
      <h1>Ilmuwan Hebat</h1>
      <Foto nama="Albert Einstein" src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Einstein_1921.jpg/200px-Einstein_1921.jpg" />
      <Foto nama="Marie Curie" src="https://upload.wikimedia.org/wikipedia/commons/thumb/7/7e/Marie_Curie_c1920.jpg/200px-Marie_Curie_c1920.jpg" />
      <Foto nama="Nikola Tesla" src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/N.Tesla.JPG/200px-N.Tesla.JPG" />
      <Foto nama="Isaac Newton" src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Portrait_of_Sir_Isaac_Newton%2C_1689.jpg/200px-Portrait_of_Sir_Isaac_Newton%2C_1689.jpg" />
    </div>
  );
}

Challenge 2: Component Bersarang 3 Level

Buat hierarki:

App └── Halaman └── Artikel └── Penulis

Setiap component menampilkan sesuatu + memanggil child-nya.

✅ Solusi
jsx
function Penulis({ nama }) {
  return <p style={{ color: "#666", fontStyle: "italic" }}>Ditulis oleh: {nama}</p>;
}

function Artikel({ judul, isi, penulis }) {
  return (
    <article style={{ marginBottom: "24px", padding: "16px", border: "1px solid #ddd", borderRadius: "8px" }}>
      <h2>{judul}</h2>
      <p>{isi}</p>
      <Penulis nama={penulis} />
    </article>
  );
}

function Halaman() {
  return (
    <main style={{ maxWidth: "600px", margin: "0 auto" }}>
      <h1>Blog Saya</h1>
      <Artikel
        judul="Belajar React Itu Mudah"
        isi="React adalah library JavaScript untuk membangun UI. Dengan component, kode jadi rapi dan reusable."
        penulis="Yazid"
      />
      <Artikel
        judul="Tips Produktif Coding"
        isi="Gunakan Pomodoro technique: 25 menit fokus, 5 menit istirahat. Ulangi 4 kali, lalu istirahat panjang."
        penulis="Budi"
      />
    </main>
  );
}

export default function App() {
  return <Halaman />;
}

Sudah paham materi ini?

Tandai sebagai selesai untuk melacak progress-mu.