Web Development

React.js untuk Pemula: Belajar Membuat Komponen UI

Tutorial lengkap belajar React.js dari nol β€” JSX, komponen, props, state, hooks, event handling, rendering daftar, dan form handling dengan contoh kode praktis

1. Pengenalan React.js

React.js adalah library JavaScript open-source yang dikembangkan oleh Meta (Facebook) untuk membangun antarmuka pengguna (UI) yang interaktif dan responsif. Diluncurkan pertama kali pada tahun 2013, React telah menjadi salah satu library frontend paling populer di dunia pengembangan web modern.

React menggunakan pendekatan komponen-based, di mana setiap bagian dari UI dibuat sebagai komponen yang mandiri dan dapat digunakan kembali. Konsep ini membuat kode lebih terstruktur, mudah di-maintain, dan scalable untuk proyek kecil maupun besar.

Mengapa Memilih React?

Keunggulan Penjelasan
Virtual DOMReact menggunakan virtual DOM untuk memperbarui UI secara efisien tanpa merender ulang seluruh halaman
Komponen ReusableSetiap komponen bisa digunakan kembali di berbagai bagian aplikasi
Ekosistem BesarRibuan library pendukung seperti React Router, Redux, Next.js, dll.
DeclarativeCukup deskripsikan apa yang ingin ditampilkan, React menangani DOM-nya
React NativeSkill React bisa langsung dipakai untuk membuat aplikasi mobile
Komunitas AktifDokumentasi lengkap, tutorial berlimpah, dan dukungan komunitas global

React vs Framework Lain

Aspek React Vue.js Angular
TipeLibraryFrameworkFramework
BahasaJavaScript/JSXJavaScript/TemplateTypeScript
Ukuran~42 KB (gzip)~33 KB (gzip)~143 KB (gzip)
Learning Curve🟑 Sedang🟒 MudahπŸ”΄ Curam
State ManagementuseState / Redux / ZustandVuex / PiniaNgRx / Services
Cocok untukSPA, Mobile App, DashboardSPA kecil-sedangEnterprise App
Diagram: Arsitektur Komponen React
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  REACT APPLICATION                    β”‚
β”‚                                                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚               Root Component (App)              β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚  β”‚
β”‚  β”‚  β”‚   Header    β”‚    β”‚     Main Content      β”‚   β”‚  β”‚
β”‚  β”‚  β”‚  Component  β”‚    β”‚      Component        β”‚   β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β” β”‚   β”‚  β”‚
β”‚  β”‚                     β”‚  β”‚ Card A β”‚ β”‚Card B β”‚ β”‚   β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚  β”‚(props) β”‚ β”‚(props)β”‚ β”‚   β”‚  β”‚
β”‚  β”‚  β”‚   Footer    β”‚    β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚   β”‚  β”‚
β”‚  β”‚  β”‚  Component  β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚             React Virtual DOM                    β”‚  β”‚
β”‚  β”‚   β€’ Menghitung perbedaan (diffing)              β”‚  β”‚
β”‚  β”‚   β€’ Hanya update bagian yang berubah            β”‚  β”‚
β”‚  β”‚   β€’ Render efisien ke DOM sesungguhnya          β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Setup Proyek React

Untuk memulai proyek React, kita menggunakan Vite yang lebih cepat dibanding Create React App (CRA). Jalankan perintah berikut di terminal:

Bash
# Buat proyek React baru dengan Vite
npm create vite@latest belajar-react -- --template react

# Masuk ke direktori proyek
cd belajar-react

# Instal dependencies
npm install

# Jalankan development server
npm run dev

# Output:
#   VITE v5.x  ready in 300 ms
#   ➜  Local:   http://localhost:5173/

Struktur Proyek

File Structure
belajar-react/
β”œβ”€β”€ node_modules/
β”œβ”€β”€ public/
β”‚   └── vite.svg
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ App.jsx           ← Komponen utama
β”‚   β”œβ”€β”€ App.css           ← Style komponen utama
β”‚   β”œβ”€β”€ main.jsx          ← Entry point
β”‚   β”œβ”€β”€ components/       ← Folder komponen
β”‚   β”‚   β”œβ”€β”€ Header.jsx
β”‚   β”‚   β”œβ”€β”€ Footer.jsx
β”‚   β”‚   └── Card.jsx
β”‚   └── index.css         ← Global styles
β”œβ”€β”€ index.html
β”œβ”€β”€ package.json
└── vite.config.js
πŸ’‘ Tips

Untuk tutorial ini, kita akan bermain-main langsung di file App.jsx. Untuk proyek nyata, sebaiknya pisahkan komponen ke dalam folder components/ agar kode lebih terorganisir dan mudah dikelola.

2. Memahami JSX

JSX (JavaScript XML) adalah sintaks perluasan JavaScript yang memungkinkan Anda menulis HTML langsung di dalam kode JavaScript. JSX bukanlah string β€” ia dikompilasi oleh Babel menjadi pemanggilan fungsi React.createElement() yang sebenarnya.

Dasar-dasar JSX

JSX β€” Dasar
// JSX sederhana β€” mengembalikan elemen HTML
function Sapaan() {
  return <h1>Halo, selamat datang di React!</h1>;
}

// JSX dengan expression β€” gunakan kurung kurawal {}
function Hitung() {
  const angka = 10 + 20;
  return <p>Hasil perhitungan: {angka}</p>;
}

// JSX dengan atribut HTML β€” gunakan camelCase
function Gambar() {
  return (
    <img
      src="/foto.jpg"
      alt="Foto profil"
      className="foto-profil"
      width={200}
    />
  );
}

// JSX harus memiliki satu root element
function Kartu() {
  return (
    <div className="kartu">
      <h2>Judul Kartu</h2>
      <p>Deskripsi kartu di sini.</p>
    </div>
  );
}

// Atau gunakan Fragment untuk wrapper tanpa DOM node
function DaftarNama() {
  return (
    <>
      <h2>Daftar Teman</h2>
      <ul>
        <li>Budi</li>
        <li>Ani</li>
      </ul>
    </>
  );
}
⚠️ Perbedaan JSX vs HTML

JSX memiliki beberapa perbedaan penting dari HTML biasa:

  • class menjadi className
  • for menjadi htmlFor
  • Gunakan camelCase untuk atribut: onclick β†’ onClick
  • Semua tag harus ditutup: <img />, <input />
  • Ekspresi JavaScript dimasukkan dengan { } bukan {{ }}

Embedding Expressions dalam JSX

JSX β€” Expressions
// Menampilkan data dinamis dengan expressions
function ProfilPengguna() {
  const nama = "Budi Santoso";
  const umur = 25;
  const isActive = true;

  return (
    <div className="profil">
      <h2>{nama}</h2>
      <p>Umur: {umur} tahun</p>
      <p>Status: {isActive ? "Online" : "Offline"}</p>
      <p>Tahun lahir: {new Date().getFullYear() - umur}</p>
    </div>
  );
}

// Memanggil fungsi di dalam JSX
function formatRupiah(angka) {
  return new Intl.NumberFormat('id-ID', {
    style: 'currency',
    currency: 'IDR'
  }).format(angka);
}

function HargaProduk() {
  const harga = 150000;
  return <p className="harga">{formatRupiah(harga)}</p>;
}

3. Komponen dan Struktur

Komponen adalah blok pembangun utama aplikasi React. Setiap komponen adalah fungsi JavaScript yang mengembalkan elemen JSX. React mendukung dua jenis komponen: Function Components (modern, direkomendasikan) dan Class Components (legacy).

Function Components

JSX β€” Function Components
// Komponen sederhana
function Tombol() {
  return <button className="btn">Klik Saya</button>;
}

// Komponen dengan multiple elemen
function Navbar() {
  return (
    <nav className="navbar">
      <h1>BeebaneLabs</h1>
      <ul>
        <li><a href="/">Beranda</a></li>
        <li><a href="/tutorial">Tutorial</a></li>
        <li><a href="/kontak">Kontak</a></li>
      </ul>
    </nav>
  );
}

// Menggunakan komponen di dalam komponen lain
function App() {
  return (
    <div className="app">
      <Navbar />
      <main>
        <h2>Selamat Datang!</h2>
        <Tombol />
      </main>
    </div>
  );
}

// Export agar bisa digunakan di file lain
export default App;

Komposisi Komponen

Kekuatan React terletak pada kemampuan menggabungkan komponen-komponen kecil menjadi UI yang kompleps. Ini disebut komposisi.

JSX β€” Komposisi Komponen
// Komponen Badge kecil
function Badge({ text }) {
  return <span className="badge">{text}</span>;
}

// Komponen Avatar
function Avatar({ src, nama }) {
  return <img src={src} alt={nama} className="avatar" />;
}

// Komponen Kartu yang menggunakan Badge dan Avatar
function KartuProfil({ pengguna }) {
  return (
    <div className="kartu-profil">
      <Avatar src={pengguna.foto} nama={pengguna.nama} />
      <h3>{pengguna.nama}</h3>
      <p>{pengguna.bio}</p>
      <Badge text={pengguna.role} />
    </div>
  );
}

// Komponen Halaman menggunakan KartuProfil
function HalamanTim() {
  const anggota = [
    { nama: "Andi", foto: "/andi.jpg", bio: "Frontend Dev", role: "Admin" },
    { nama: "Sari", foto: "/sari.jpg", bio: "Backend Dev", role: "Member" },
    { nama: "Dimas", foto: "/dimas.jpg", bio: "UI Designer", role: "Member" },
  ];

  return (
    <div className="halaman-tim">
      <h1>Tim Kami</h1>
      <div className="kartu-grid">
        {anggota.map((a) => (
          <KartuProfil key={a.nama} pengguna={a} />
        ))}
      </div>
    </div>
  );
}
Diagram: Struktur Komposisi Komponen
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚               HalamanTim                 β”‚
β”‚                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚KartuProfil β”‚ β”‚KartuPr.β”‚ β”‚KartuProfilβ”‚ β”‚
β”‚  β”‚            β”‚ β”‚        β”‚ β”‚          β”‚ β”‚
β”‚  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚β”Œβ”€β”€β”€β”€β”€β”€β”β”‚ β”‚β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚
β”‚  β”‚ β”‚ Avatar β”‚ β”‚ β”‚β”‚Avatarβ”‚β”‚ β”‚β”‚ Avatar β”‚β”‚ β”‚
β”‚  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚β””β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚
β”‚  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚β”Œβ”€β”€β”€β”€β”€β”€β”β”‚ β”‚β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚
β”‚  β”‚ β”‚ Badge  β”‚ β”‚ β”‚β”‚Badge β”‚β”‚ β”‚β”‚ Badge  β”‚β”‚ β”‚
β”‚  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚β””β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

4. Props: Mengirim Data Antar Komponen

Props (properties) adalah cara untuk mengirim data dari komponen induk ke komponen anak. Props bersifat read-only β€” komponen anak tidak boleh mengubah props yang diterimanya. Ini menjaga aliran data yang searah (unidirectional data flow).

Menggunakan Props

JSX β€” Props
// Komponen menerima props sebagai argumen fungsi
function Sapaan({ nama, pesan }) {
  return (
    <div className="sapaan">
      <h2>Halo, {nama}!</h2>
      <p>{pesan}</p>
    </div>
  );
}

// Mengirim props dari komponen induk
function App() {
  return (
    <div>
      <Sapaan nama="Budi" pesan="Selamat datang di React!" />
      <Sapaan nama="Sari" pesan="Semangat belajar ya!" />
      <Sapaan nama="Andi" pesan="React itu seru!" />
    </div>
  );
}

// Props dengan nilai default
function KartuJudul({ judul = "Judul Default", subjudul = "" }) {
  return (
    <div className="kartu-judul">
      <h2>{judul}</h2>
      {subjudul && <p className="subjudul">{subjudul}</p>}
    </div>
  );
}

// Props bertipe array
function DaftarItem({ items }) {
  return (
    <ul className="daftar-item">
      {items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
}

// Contoh penggunaan:
// <DaftarItem items={["Roti", "Susu", "Telur", "Kopi"]} />

// Props dengan children
function Panel({ judul, children }) {
  return (
    <div className="panel">
      <h3 className="panel-judul">{judul}</h3>
      <div className="panel-konten">
        {children}
      </div>
    </div>
  );
}

// Contoh penggunaan children:
// <Panel judul="Pengaturan Akun">
//   <input placeholder="Nama" />
//   <input placeholder="Email" />
//   <button>Simpan</button>
// </Panel>
⚠️ Props Tidak Boleh Diubah!

Props adalah read-only. Jangan pernah mencoba mengubah nilai props di dalam komponen anak. Jika Anda perlu data yang berubah, gunakan state atau callback functions sebagai gantinya. Melanggar aturan ini dapat menyebabkan bug yang sulit dilacak.

5. State: Data Dinamis dalam Komponen

State adalah data yang dimiliki dan dikelola oleh komponen itu sendiri. Berbeda dengan props yang datang dari luar, state bisa berubah seiring waktu β€” misalnya ketika pengguna mengetik di input, mengklik tombol, atau data dari API tiba. Ketika state berubah, React secara otomatis me-render ulang komponen tersebut.

State dengan Class Component (Legacy)

JSX β€” State (Class)
// State pada class component (hanya untuk referensi, gunakan hooks)
class HitungMundur extends React.Component {
  constructor(props) {
    super(props);
    this.state = { detik: 60 };
  }

  componentDidMount() {
    this.interval = setInterval(() => {
      this.setState((prev) => ({
        detik: prev.detik - 1
      }));
    }, 1000);
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  render() {
    return <h2>Sisa waktu: {this.state.detik} detik</h2>;
  }
}

State dengan Hooks (Modern β€” Direkomendasikan)

Di React modern, kita menggunakan hook useState untuk mengelola state dalam function components. Ini lebih sederhana dan mudah dipahami.

JSX β€” useState Hook
import { useState } from 'react';

// Counter sederhana dengan useState
function Counter() {
  // useState mengembalikan [nilaiSaatIni, fungsiUbah]
  const [hitungan, setHitungan] = useState(0);

  return (
    <div className="counter">
      <h2>Hitungan: {hitungan}</h2>
      <button onClick={() => setHitungan(hitungan + 1)}>
        Tambah (+1)
      </button>
      <button onClick={() => setHitungan(hitungan - 1)}>
        Kurang (-1)
      </button>
      <button onClick={() => setHitungan(0)}>
        Reset
      </button>
    </div>
  );
}

// Multiple state dalam satu komponen
function FormProfil() {
  const [nama, setNama] = useState('');
  const [email, setEmail] = useState('');
  const [umur, setUmur] = useState(0);

  return (
    <form>
      <input
        value={nama}
        onChange={(e) => setNama(e.target.value)}
        placeholder="Nama"
      />
      <input
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
      />
      <input
        type="number"
        value={umur}
        onChange={(e) => setUmur(Number(e.target.value))}
        placeholder="Umur"
      />
      <p>Profil: {nama}, {email}, {umur} tahun</p>
    </form>
  );
}

// State dengan object
function TodoApp() {
  const [todo, setTodo] = useState({
    teks: '',
    selesai: false
  });

  const toggleSelesai = () => {
    setTodo(prev => ({ ...prev, selesai: !prev.selesai }));
  };

  return (
    <div>
      <p>{todo.teks} β€” {todo.selesai ? "βœ… Selesai" : "⏳ Belum"}</p>
      <button onClick={toggleSelesai}>Toggle Selesai</button>
    </div>
  );
}

6. React Hooks: useState & useEffect

React Hooks diperkenalkan di React 16.8 dan mengubah cara kita menulis komponen. Hooks memungkinkan function components memiliki state dan lifecycle methods yang sebelumnya hanya tersedia di class components.

useState Hook

useState adalah hook yang paling sering digunakan. Ia mengembalikan sepasang nilai: state saat ini dan fungsi untuk memperbaruinya.

JSX β€” useState Detail
import { useState } from 'react';

function KeranjangBelanja() {
  const [items, setItems] = useState([]);

  const tambahItem = (nama) => {
    // Gunakan callback jika state baru bergantung pada state lama
    setItems(prev => [...prev, { id: Date.now(), nama }]);
  };

  const hapusItem = (id) => {
    setItems(prev => prev.filter(item => item.id !== id));
  };

  return (
    <div className="keranjang">
      <h2>Keranjang ({items.length} item)</h2>
      <ul>
        {items.map(item => (
          <li key={item.id}>
            {item.nama}
            <button onClick={() => hapusItem(item.id)}>Hapus</button>
          </li>
        ))}
      </ul>
      <button onClick={() => tambahItem("Produk Baru")}>
        Tambah Item
      </button>
    </div>
  );
}

useEffect Hook

useEffect digunakan untuk efek samping (side effects) seperti fetching data, memanipulasi DOM, berlangganan event, atau mengatur timer. Ia menjalankan kode setelah render dan bisa diatur kapan harus berjalan kembali.

JSX β€” useEffect
import { useState, useEffect } from 'react';

// useEffect berjalan setiap render (default)
function WaktuSekarang() {
  const [waktu, setWaktu] = useState(new Date());

  // Berjalan setelah setiap render
  useEffect(() => {
    const timer = setInterval(() => {
      setWaktu(new Date());
    }, 1000);

    // Cleanup function β€” dijalankan saat komponen unmount
    return () => clearInterval(timer);
  }, []); // Array kosong = hanya sekali saat mount

  return <p>Waktu: {waktu.toLocaleTimeString('id-ID')}</p>;
}

// useEffect dengan dependency
function DetailProduk({ idProduk }) {
  const [produk, setProduk] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    setLoading(true);
    // Fetch data saat idProduk berubah
    fetch(`/api/produk/${idProduk}`)
      .then(res => res.json())
      .then(data => {
        setProduk(data);
        setLoading(false);
      })
      .catch(err => {
        console.error("Gagal memuat produk:", err);
        setLoading(false);
      });
  }, [idProduk]); // Berjalan saat idProduk berubah

  if (loading) return <p>Memuat data...</p>;
  if (!produk) return <p>Produk tidak ditemukan</p>;

  return (
    <div className="detail-produk">
      <h2>{produk.nama}</h2>
      <p>{produk.deskripsi}</p>
      <p className="harga">Rp {produk.harga.toLocaleString('id-ID')}</p>
    </div>
  );
}

// useEffect untuk mengubah document title
function CounterDenganTitle() {
  const [hitungan, setHitungan] = useState(0);

  useEffect(() => {
    document.title = `Hitungan: ${hitungan}`;
  }, [hitungan]); // Berjalan saat hitungan berubah

  return (
    <div>
      <h2>{hitungan}</h2>
      <button onClick={() => setHitungan(c => c + 1)}>+1</button>
    </div>
  );
}
πŸ’‘ Kapan useEffect Berjalan?
Dependency ArrayKapan Berjalan
useEffect(fn)Setelah setiap render
useEffect(fn, [])Hanya sekali saat komponen pertama kali mount
useEffect(fn, [a, b])Saat komponen mount dan saat a atau b berubah

7. Event Handling

React menggunakan sistem event yang mirip dengan DOM events, tetapi dinamai dengan camelCase. Event handler dikirim sebagai props ke elemen-elemen JSX.

JSX β€” Event Handling
function ContohEvent() {
  // Handler sederhana
  const handleClick = () => {
    alert("Tombol diklik!");
  };

  // Handler dengan parameter
  const handleItemClick = (nama) => {
    alert(`Item dipilih: ${nama}`);
  };

  // Handler dengan event object
  const handleInputChange = (e) => {
    console.log("Nilai input:", e.target.value);
  };

  // Handler untuk form submission
  const handleSubmit = (e) => {
    e.preventDefault(); // Mencegah reload halaman
    alert("Form disubmit!");
  };

  // Handler untuk keyboard event
  const handleKeyPress = (e) => {
    if (e.key === 'Enter') {
      alert("Enter ditekan!");
    }
  };

  return (
    <div>
      {/* Event handler langsung */}
      <button onClick={handleClick}>Klik Saya</button>

      {/* Inline handler (hanya untuk fungsi singkat) */}
      <button onClick={() => console.log("diklik")}>Log</button>

      {/* Handler dengan parameter */}
      <button onClick={() => handleItemClick("Laptop")}>
        Pilih Laptop
      </button>

      {/* Input event */}
      <input
        onChange={handleInputChange}
        onKeyPress={handleKeyPress}
        placeholder="Ketik sesuatu..."
      />

      {/* Form submission */}
      <form onSubmit={handleSubmit}>
        <input placeholder="Nama" />
        <button type="submit">Kirim</button>
      </form>
    </div>
  );
}

// Mencegah event propagation (stopPropagation)
function KartuKlik({ judul, onKlik }) {
  const handleKlikKartu = (e) => {
    e.stopPropagation(); // Mencegah event ke parent
    onKlik(judul);
  };

  return (
    <div className="kartu" onClick={handleKlikKartu}>
      <h3>{judul}</h3>
      <p>Klik kartu ini</p>
    </div>
  );
}

8. Conditional Rendering

React memungkinkan Anda merender elemen secara kondisional berdasarkan kondisi tertentu. Ini sangat berguna untuk menampilkan loading state, error messages, konten terproteksi, dan sebagainya.

JSX β€” Conditional Rendering
// 1. Ternary operator
function StatusPengguna({ isLoggedIn }) {
  return (
    <div>
      {isLoggedIn ? (
        <h2>Selamat datang kembali!</h2>
      ) : (
        <h2>Silakan login terlebih dahulu</h2>
      )}
    </div>
  );
}

// 2. Logical AND (&&) untuk render kondisional sederhana
function Notifikasi({ pesan }) {
  return (
    <div>
      {pesan && <div className="notifikasi">{pesan}</div>}
    </div>
  );
}

// 3. Early return pattern
function DetailProfil({ pengguna }) {
  // Jika belum ada data, tampilkan loading
  if (!pengguna) {
    return <div className="loading">Memuat profil...</div>;
  }

  // Jika ada error
  if (pengguna.error) {
    return <div className="error">Gagal memuat profil</div>;
  }

  // Normal render
  return (
    <div className="profil">
      <h2>{pengguna.nama}</h2>
      <p>{pengguna.email}</p>
    </div>
  );
}

// 4. Switch-case pattern dengan helper function
function LabelPrioritas({ level }) {
  const renderLabel = () => {
    switch (level) {
      case 'tinggi':
        return <span className="label label-merah">πŸ”΄ Tinggi</span>;
      case 'sedang':
        return <span className="label label-kuning">🟑 Sedang</span>;
      case 'rendah':
        return <span className="label label-hijau">🟒 Rendah</span>;
      default:
        return <span className="label">Tidak diketahui</span>;
    }
  };

  return <div className="prioritas">{renderLabel()}</div>;
}

9. Rendering Daftar & Keys

Rendering daftar data adalah salah satu kebutuhan paling umum dalam pengembangan frontend. Di React, kita menggunakan metode map() untuk mengubah array data menjadi elemen JSX. Setiap elemen dalam daftar harus memiliki key yang unik.

JSX β€” Rendering Lists
// Daftar sederhana
function DaftarMahasiswa() {
  const mahasiswa = [
    { id: 1, nama: "Budi", jurusan: "Informatika", ipk: 3.8 },
    { id: 2, nama: "Sari", jurusan: "Sistem Informasi", ipk: 3.5 },
    { id: 3, nama: "Andi", jurusan: "Teknik Komputer", ipk: 3.9 },
    { id: 4, nama: "Maya", jurusan: "Informatika", ipk: 3.7 },
    { id: 5, nama: "Rizki", jurusan: "Sistem Informasi", ipk: 3.6 },
  ];

  return (
    <div className="daftar-mahasiswa">
      <h2>Daftar Mahasiswa</h2>
      <table>
        <thead>
          <tr>
            <th>No</th>
            <th>Nama</th>
            <th>Jurusan</th>
            <th>IPK</th>
          </tr>
        </thead>
        <tbody>
          {mahasiswa.map((mhs, index) => (
            <tr key={mhs.id}>
              <td>{index + 1}</td>
              <td>{mhs.nama}</td>
              <td>{mhs.jurusan}</td>
              <td>{mhs.ipk}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

// Daftar dengan filter dan sorting
function ProdukList({ kategori }) {
  const semuaProduk = [
    { id: 1, nama: "Laptop ASUS", harga: 12000000, kat: "elektronik" },
    { id: 2, nama: "Kaos Polos", harga: 85000, kat: "pakaian" },
    { id: 3, nama: "Mouse Logitech", harga: 250000, kat: "elektronik" },
    { id: 4, nama: "Celana Jeans", harga: 350000, kat: "pakaian" },
    { id: 5, nama: "Keyboard Mekanik", harga: 800000, kat: "elektronik" },
  ];

  const produkFiltered = semuaProduk
    .filter(p => p.kat === kategori)
    .sort((a, b) => a.harga - b.harga);

  return (
    <div className="produk-list">
      <h2>Produk {kategori}</h2>
      {produkFiltered.length === 0 ? (
        <p>Tidak ada produk dalam kategori ini.</p>
      ) : (
        <ul>
          {produkFiltered.map(produk => (
            <li key={produk.id}>
              <span>{produk.nama}</span>
              <span>Rp {produk.harga.toLocaleString('id-ID')}</span>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}
⚠️ Mengapa Key Penting?

React menggunakan key untuk melacak elemen mana yang berubah, ditambah, atau dihapus. Tanpa key yang tepat, React harus me-render ulang seluruh daftar β€” ini tidak efisien. Gunakan ID unik dari data (bukan index array) sebagai key. Hanya gunakan index sebagai key terakhir jika tidak ada ID yang tersedia.

10. Form Handling

Form di React menggunakan konsep controlled components, di mana nilai input dikontrol oleh state React. Ini memudahkan validasi, manipulasi data, dan integrasi dengan API.

JSX β€” Form Handling
import { useState } from 'react';

function FormRegistrasi() {
  const [formData, setFormData] = useState({
    nama: '',
    email: '',
    password: '',
    konfirmasiPassword: '',
    setuju: false,
  });

  const [errors, setErrors] = useState({});
  const [submitted, setSubmitted] = useState(false);

  const handleChange = (e) => {
    const { name, value, type, checked } = e.target;
    setFormData(prev => ({
      ...prev,
      [name]: type === 'checkbox' ? checked : value,
    }));
    // Hapus error saat user mengetik
    if (errors[name]) {
      setErrors(prev => ({ ...prev, [name]: '' }));
    }
  };

  const validate = () => {
    const newErrors = {};

    if (!formData.nama.trim()) {
      newErrors.nama = 'Nama wajib diisi';
    }
    if (!formData.email.includes('@')) {
      newErrors.email = 'Email tidak valid';
    }
    if (formData.password.length < 6) {
      newErrors.password = 'Password minimal 6 karakter';
    }
    if (formData.password !== formData.konfirmasiPassword) {
      newErrors.konfirmasiPassword = 'Password tidak cocok';
    }
    if (!formData.setuju) {
      newErrors.setuju = 'Anda harus menyetujui syarat & ketentuan';
    }

    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const handleSubmit = (e) => {
    e.preventDefault();

    if (validate()) {
      console.log("Data valid:", formData);
      setSubmitted(true);
      // Kirim data ke API di sini
    }
  };

  if (submitted) {
    return (
      <div className="success-message">
        <h2>βœ… Registrasi Berhasil!</h2>
        <p>Selamat datang, {formData.nama}!</p>
      </div>
    );
  }

  return (
    <form onSubmit={handleSubmit} className="form-registrasi">
      <h2>Form Registrasi</h2>

      <div className="form-group">
        <label htmlFor="nama">Nama Lengkap</label>
        <input
          id="nama"
          name="nama"
          value={formData.nama}
          onChange={handleChange}
          placeholder="Masukkan nama"
        />
        {errors.nama && <span className="error">{errors.nama}</span>}
      </div>

      <div className="form-group">
        <label htmlFor="email">Email</label>
        <input
          id="email"
          name="email"
          type="email"
          value={formData.email}
          onChange={handleChange}
          placeholder="contoh@email.com"
        />
        {errors.email && <span className="error">{errors.email}</span>}
      </div>

      <div className="form-group">
        <label htmlFor="password">Password</label>
        <input
          id="password"
          name="password"
          type="password"
          value={formData.password}
          onChange={handleChange}
          placeholder="Minimal 6 karakter"
        />
        {errors.password && <span className="error">{errors.password}</span>}
      </div>

      <div className="form-group">
        <label htmlFor="konfirmasiPassword">Konfirmasi Password</label>
        <input
          id="konfirmasiPassword"
          name="konfirmasiPassword"
          type="password"
          value={formData.konfirmasiPassword}
          onChange={handleChange}
          placeholder="Ulangi password"
        />
        {errors.konfirmasiPassword && (
          <span className="error">{errors.konfirmasiPassword}</span>
        )}
      </div>

      <div className="form-group">
        <label>
          <input
            name="setuju"
            type="checkbox"
            checked={formData.setuju}
            onChange={handleChange}
          />
          Saya menyetujui syarat & ketentuan
        </label>
        {errors.setuju && <span className="error">{errors.setuju}</span>}
      </div>

      <button type="submit" className="btn-primary">Daftar</button>
    </form>
  );
}

export default FormRegistrasi;
πŸ’‘ Controlled vs Uncontrolled Components

Pada controlled components, nilai input sepenuhnya dikontrol oleh state React melalui value dan onChange. Sedangkan uncontrolled components menggunakan ref untuk mengakses nilai DOM secara langsung. Controlled components lebih umum karena memberikan kontrol penuh atas data form.

11. Quiz: Uji Pemahamanmu!

Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang React.js:

Pertanyaan 1: Apa kepanjangan dari JSX dalam konteks React?

a) JavaScript XML
b) Java Syntax Extension
c) JSON XML Syntax
d) JavaScript Extension

Pertanyaan 2: Apa perbedaan utama antara props dan state di React?

a) Props bisa diubah, state tidak bisa
b) Props dikirim dari induk dan bersifat read-only, state dikelola oleh komponen itu sendiri
c) Props untuk styling, state untuk data
d) Tidak ada perbedaan

Pertanyaan 3: Hook apa yang digunakan untuk menjalankan efek samping (side effects) dalam function component?

a) useState
b) useReducer
c) useEffect
d) useContext

Pertanyaan 4: Mengapa setiap elemen dalam daftar (list) harus memiliki key yang unik?

a) Agar styling bisa diterapkan
b) Agar React dapat melacak elemen yang berubah, ditambah, atau dihapus secara efisien
c) Agar elemen bisa di-sort
d) Agar elemen bisa diklik

Pertanyaan 5: Apa yang terjadi saat useState dipanggil dengan nilai baru?

a) Halaman di-reload sepenuhnya
b) React me-render ulang komponen yang memiliki state tersebut
c) State berubah tetapi UI tidak diperbarui
d) Semua komponen dalam aplikasi di-render ulang
πŸ” Zoom
100%
🎨 Tema