Bab 1: Quick Start — Kenalan Sama React
⏱ 7 menit bacaApa Itu React?
Bayangin kamu lagi main LEGO. Setiap balok LEGO punya bentuk dan fungsi sendiri — ada yang jadi atap, ada yang jadi dinding, ada yang jadi jendela. Kamu tinggal rakit balok-balok itu jadi rumah, kastil, atau apapun yang kamu mau.
React itu LEGO-nya web development.
Setiap "balok" di React disebut Component. Satu component bisa jadi tombol, bisa jadi navbar, bisa jadi satu halaman penuh. Kamu bikin component kecil-kecil, terus rakit jadi website utuh.
Kenapa React?
- Reusable — Bikin component sekali, pakai berkali-kali. Tombol "Beli" yang sama bisa muncul di 50 halaman berbeda.
- Terstruktur — Kode kamu rapi karena setiap bagian UI punya "rumahnya" sendiri.
- Cepat — React cuma update bagian yang berubah, bukan seluruh halaman (ini namanya Virtual DOM).
- Populer — Instagram, Facebook, Netflix, Tokopedia, Gojek — semua pakai React.
Membuat Component Pertama
Component di React itu cuma fungsi JavaScript yang return markup (HTML). Sesimpel itu.
function Tombol() {
return (
<button>Klik Saya</button>
);
}Coba sendiri: Edit kode di bawah dan lihat hasilnya langsung!
Itu udah component! Namanya Tombol. Dia return satu elemen <button>.
Aturan Penting
- Nama component HARUS huruf kapital —
Tombol✅,tombol❌ - Return-nya harus satu elemen pembungkus — kalau mau return banyak elemen, bungkus pakai
<div>atau<>...</>
// ❌ SALAH — return 2 elemen tanpa pembungkus
function Profil() {
return (
<h1>Yazid</h1>
<p>Web Developer</p>
);
}
// ✅ BENAR — dibungkus Fragment (<>...</>)
function Profil() {
return (
<>
<h1>Yazid</h1>
<p>Web Developer</p>
</>
);
}Kenapa Harus Huruf Kapital?
React membedakan component buatan kamu vs tag HTML biasa berdasarkan huruf pertama:
<button>→ React anggap ini tag HTML biasa<Tombol>→ React anggap ini component buatan kamu
Kalau kamu tulis <tombol>, React bakal cari tag HTML bernama "tombol" — yang tentu nggak ada. Hasilnya: error.
Menyusun Component (Nesting)
Kekuatan React ada di komposisi — component bisa dipanggil di dalam component lain.
function Tombol() {
return <button>Klik Saya</button>;
}
function Halaman() {
return (
<div>
<h1>Selamat Datang</h1>
<Tombol />
<Tombol />
<Tombol />
</div>
);
}Lihat? Halaman memanggil Tombol tiga kali. Hasilnya: 3 tombol muncul di halaman. Ini kayak kamu pakai balok LEGO yang sama berulang kali.
Bayangin component itu resep:
<Tombol />= resep bikin tombol<Navbar />= resep bikin navigation bar<Halaman />= resep bikin halaman yang pakai resep Tombol dan Navbar di dalamnya
Kamu nggak perlu tulis ulang kode tombol setiap kali butuh tombol. Cukup panggil <Tombol />.
JSX — HTML di Dalam JavaScript
Markup yang kamu lihat di atas (<button>, <div>, dll) bukan HTML biasa. Itu namanya JSX (JavaScript XML).
JSX = cara menulis "HTML" di dalam file JavaScript.
// Ini JSX, bukan HTML!
function Kartu() {
return (
<div className="kartu">
<h2>Judul</h2>
<p>Deskripsi</p>
</div>
);
}Perbedaan JSX vs HTML
| HTML | JSX | Kenapa? |
|---|---|---|
class="..." | className="..." | class sudah jadi keyword di JavaScript |
<br> | <br /> | JSX wajib tutup semua tag |
<img> | <img /> | Sama — wajib self-closing |
for="..." | htmlFor="..." | for sudah jadi keyword di JavaScript |
Kenapa Pakai JSX?
Karena UI dan logika itu saling terkait. Daripada pisah HTML di satu file dan JS di file lain, React gabungin keduanya di satu tempat. Jadi kamu bisa lihat "tampilan + perilaku" component dalam satu pandangan.
Menampilkan Data dengan Curly Braces {}
Di JSX, kamu bisa "nyisipin" JavaScript pakai kurung kurawal {}:
function ProfilUser() {
const nama = "Yazid Akbar";
const umur = 25;
const foto = "https://example.com/foto.jpg";
return (
<div>
<img src={foto} alt={nama} />
<h1>{nama}</h1>
<p>Umur: {umur} tahun</p>
<p>Tahun lahir: {2024 - umur}</p>
</div>
);
}Apa aja yang bisa masuk {}?
- Variabel:
{nama} - Ekspresi:
{2024 - umur} - Pemanggilan fungsi:
{nama.toUpperCase()} - Ternary:
{umur >= 17 ? "Dewasa" : "Anak-anak"}
Bayangin kamu bikin template surat:
Kepada Yth. , kami informasikan bahwa saldo Anda sebesar ...
Kurung kurawal di JSX fungsinya sama — tempat "lubang" yang diisi data dinamis.
Conditional Rendering — Tampilkan Sesuai Kondisi
Kadang kamu mau tampilkan sesuatu hanya kalau kondisi tertentu terpenuhi.
Cara 1: if/else biasa
function Salam({ sudahLogin }) {
if (sudahLogin) {
return <h1>Selamat datang kembali!</h1>;
}
return <h1>Silakan login dulu</h1>;
}Cara 2: Ternary operator (lebih ringkas)
function Salam({ sudahLogin }) {
return (
<h1>{sudahLogin ? "Selamat datang kembali!" : "Silakan login dulu"}</h1>
);
}Cara 3: && (tampilkan kalau true, sembunyikan kalau false)
function Notifikasi({ jumlahPesan }) {
return (
<div>
<h1>Dashboard</h1>
{jumlahPesan > 0 && <p>Kamu punya {jumlahPesan} pesan baru!</p>}
</div>
);
}Kalau jumlahPesan = 0, paragraf nggak muncul. Kalau > 0, muncul.
// ❌ BUG! Kalau jumlah = 0, akan render angka "0" di layar
{jumlah && <p>Ada {jumlah} item</p>}
// ✅ BENAR — pakai perbandingan eksplisit
{jumlah > 0 && <p>Ada {jumlah} item</p>}Kenapa? Karena 0 && <p>...</p> hasilnya 0 (falsy tapi bukan false), dan React tetap render angka 0.
Rendering List — Tampilkan Data Array
Kalau kamu punya array data, gunakan .map() untuk render jadi list:
function DaftarBuah() {
const buah = ["Apel", "Mangga", "Jeruk", "Durian"];
return (
<ul>
{buah.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}Kenapa Harus Ada key?
key itu "KTP" setiap item di list. React pakai key untuk tahu item mana yang berubah, ditambah, atau dihapus.
// ✅ BAGUS — pakai ID unik
{produk.map((p) => (
<li key={p.id}>{p.nama}</li>
))}
// ⚠️ KURANG BAGUS — pakai index (bisa bug kalau urutan berubah)
{produk.map((p, index) => (
<li key={index}>{p.nama}</li>
))}Contoh Lebih Lengkap: Daftar Kontak
function DaftarKontak() {
const kontak = [
{ id: 1, nama: "Budi", telp: "0812-1234-5678" },
{ id: 2, nama: "Ani", telp: "0813-9876-5432" },
{ id: 3, nama: "Citra", telp: "0856-1111-2222" },
];
return (
<div>
<h2>Kontak Saya</h2>
{kontak.map((orang) => (
<div key={orang.id} style={{ marginBottom: "10px" }}>
<strong>{orang.nama}</strong>
<p>{orang.telp}</p>
</div>
))}
</div>
);
}Merespons Event — Bikin Tombol Interaktif
Component bisa merespons aksi user (klik, ketik, hover, dll) lewat event handler:
function TombolAlert() {
function handleKlik() {
alert("Tombol diklik!");
}
return (
<button onClick={handleKlik}>
Klik Saya
</button>
);
}Aturan Penting
// ✅ BENAR — pass fungsi (tanpa tanda kurung)
<button onClick={handleKlik}>
// ❌ SALAH — ini LANGSUNG dipanggil saat render!
<button onClick={handleKlik()}>Kenapa? handleKlik() dengan kurung artinya "panggil sekarang". Tanpa kurung artinya "simpan dulu, panggil nanti kalau diklik".
Event Handler Inline
Kalau logikanya pendek, bisa langsung tulis inline:
<button onClick={() => alert("Halo!")}>
Sapa
</button>Contoh: Tombol Counter
function Counter() {
let angka = 0;
function tambah() {
angka = angka + 1;
console.log(angka); // Angka bertambah di console...
// ...tapi tampilan TIDAK berubah! 😱
}
return (
<div>
<p>Angka: {angka}</p>
<button onClick={tambah}>+1</button>
</div>
);
}Lho kok tampilannya nggak berubah? Karena React nggak tahu kalau angka berubah. Kita butuh State!
State — Memori Component
State adalah data yang "diingat" oleh component dan bisa berubah seiring waktu. Kalau state berubah, React otomatis re-render (gambar ulang) component-nya.
import { useState } from 'react';
function Counter() {
const [angka, setAngka] = useState(0);
function tambah() {
setAngka(angka + 1); // Update state → React re-render
}
return (
<div>
<p>Angka: {angka}</p>
<button onClick={tambah}>+1</button>
</div>
);
}Cara Kerja useState
const [nilaiSekarang, fungsiUntukUpdate] = useState(nilaiAwal);nilaiSekarang— nilai state saat inifungsiUntukUpdate— fungsi untuk mengubah statenilaiAwal— nilai pertama kali (hanya dipakai saat render pertama)
Bayangin papan skor di pertandingan basket:
- State = angka di papan skor (bisa berubah)
- setState = operator yang pencet tombol untuk ganti angka
- Re-render = papan skor refresh menampilkan angka baru
Kalau kamu cuma teriak "SKOR BERUBAH!" tanpa pencet tombol (tanpa setState), papan skor tetap nunjukin angka lama.
Setiap Component Punya State Sendiri
function App() {
return (
<div>
<Counter /> {/* Punya state sendiri: 0, 1, 2, ... */}
<Counter /> {/* Punya state sendiri: 0, 1, 2, ... */}
</div>
);
}Dua <Counter /> di atas independen. Klik satu nggak ngaruh ke yang lain. Masing-masing punya "memori" sendiri.
Hooks — Fungsi Spesial React
useState itu salah satu Hook. Hook adalah fungsi spesial yang dimulai dengan kata use.
Aturan Hook (WAJIB diikuti!)
- Hanya panggil di level teratas component — jangan di dalam if, loop, atau fungsi nested
- Hanya panggil di dalam component React — jangan di fungsi biasa
// ❌ SALAH
function Counter() {
if (true) {
const [angka, setAngka] = useState(0); // Hook di dalam if!
}
}
// ✅ BENAR
function Counter() {
const [angka, setAngka] = useState(0); // Hook di level teratas
// ...
}Kenapa Ada Aturan Ini?
React melacak Hook berdasarkan urutan pemanggilan. Kalau kamu taruh Hook di dalam if, urutannya bisa berubah-ubah tiap render — React jadi bingung Hook mana yang mana.
Berbagi Data Antar Component (Lifting State Up)
Kadang kamu mau 2 component sinkron — kalau satu berubah, yang lain ikut berubah.
Masalah: State Terpisah
function App() {
return (
<div>
<Counter /> {/* angka: 3 */}
<Counter /> {/* angka: 0 — nggak ikut berubah */}
</div>
);
}Solusi: Angkat State ke Parent
import { useState } from 'react';
function App() {
const [angka, setAngka] = useState(0);
return (
<div>
<h1>Angka: {angka}</h1>
<Tombol onClick={() => setAngka(angka + 1)} label="+1" />
<Tombol onClick={() => setAngka(angka - 1)} label="-1" />
</div>
);
}
function Tombol({ onClick, label }) {
return <button onClick={onClick}>{label}</button>;
}Sekarang kedua tombol mengontrol satu state yang sama di parent. Ini namanya "Lifting State Up" — angkat state ke component terdekat yang membutuhkannya.
- Tanpa lifting state: Setiap orang punya TV sendiri. Ganti channel di TV kamu nggak ngaruh ke TV orang lain.
- Dengan lifting state: Satu TV, banyak remote. Siapapun yang pencet remote, TV yang sama berubah.
Props — Kirim Data ke Component Anak
Props (properties) adalah cara mengirim data dari parent ke child component.
function KartuProduk({ nama, harga, stok }) {
return (
<div className="kartu">
<h3>{nama}</h3>
<p>Rp {harga.toLocaleString()}</p>
<p>{stok > 0 ? `Stok: ${stok}` : "Habis"}</p>
</div>
);
}
function Toko() {
return (
<div>
<KartuProduk nama="Laptop" harga={15000000} stok={5} />
<KartuProduk nama="Mouse" harga={250000} stok={0} />
<KartuProduk nama="Keyboard" harga={500000} stok={12} />
</div>
);
}Props vs State
| Props | State |
|---|---|
| Dikirim dari parent | Dimiliki component sendiri |
| Read-only (nggak bisa diubah child) | Bisa diubah lewat setState |
| Kayak argumen fungsi | Kayak variabel lokal yang "diingat" |
- Props = pesan yang dikirim bos ke karyawan ("Kerjakan ini dengan data ini")
- State = catatan pribadi karyawan ("Saya sudah selesai 3 dari 5 tugas")
Karyawan nggak bisa mengubah pesan dari bos (props immutable), tapi bisa update catatan pribadinya sendiri (state mutable).
⚠️ Jebakan Umum Pemula React
1. Lupa import useState
// ❌ Error: useState is not defined
function App() {
const [count, setCount] = useState(0);
}
// ✅ Tambahkan import di atas
import { useState } from 'react';2. Mutasi state langsung
// ❌ SALAH — React nggak tahu state berubah
const [items, setItems] = useState(["apel"]);
items.push("mangga"); // Mutasi langsung!
// ✅ BENAR — buat array baru
setItems([...items, "mangga"]);3. State update nggak langsung terasa
function handleKlik() {
setAngka(angka + 1);
console.log(angka); // Masih angka LAMA! 😱
// State baru berlaku di render BERIKUTNYA
}4. Render infinite loop
// ❌ INFINITE LOOP — setState dipanggil setiap render!
function App() {
const [x, setX] = useState(0);
setX(x + 1); // Ini dipanggil setiap render → trigger render lagi → loop!
return <p>{x}</p>;
}
// ✅ BENAR — setState hanya di event handler atau useEffect
function App() {
const [x, setX] = useState(0);
return <button onClick={() => setX(x + 1)}>{x}</button>;
}5. Component name lowercase
// ❌ React anggap ini HTML tag (yang nggak ada)
function kartuProduk() { ... }
<kartuProduk />
// ✅ Huruf kapital
function KartuProduk() { ... }
<KartuProduk />🏋️ Challenge
Challenge 1: Kartu Profil
Buat component KartuProfil yang menerima props nama, pekerjaan, dan kota. Tampilkan dalam format:
┌─────────────────────┐
│ Budi Santoso │
│ Software Engineer │
│ 📍 Jakarta │
└─────────────────────┘
Panggil component ini 3 kali dengan data berbeda.
💡 Hint
Gunakan destructuring di parameter: function KartuProfil({ nama, pekerjaan, kota })
✅ Solusi
function KartuProfil({ nama, pekerjaan, kota }) {
return (
<div style={{ border: "1px solid #ccc", padding: "16px", borderRadius: "8px", marginBottom: "12px" }}>
<h3>{nama}</h3>
<p>{pekerjaan}</p>
<p>📍 {kota}</p>
</div>
);
}
function App() {
return (
<div>
<KartuProfil nama="Budi Santoso" pekerjaan="Software Engineer" kota="Jakarta" />
<KartuProfil nama="Ani Wijaya" pekerjaan="UI Designer" kota="Bandung" />
<KartuProfil nama="Citra Dewi" pekerjaan="Data Analyst" kota="Surabaya" />
</div>
);
}Challenge 2: Toggle Tampilkan/Sembunyikan
Buat component dengan tombol yang toggle teks. Kalau diklik, teks muncul. Diklik lagi, teks hilang.
- State:
tampil(true/false) - Tombol text: "Tampilkan" kalau tersembunyi, "Sembunyikan" kalau terlihat
- Teks yang di-toggle: "Ini adalah teks rahasia! 🤫"
💡 Hint
Gunakan useState(false) dan toggle dengan setTampil(!tampil). Pakai && untuk conditional render.
✅ Solusi
import { useState } from 'react';
function RahasiaTeks() {
const [tampil, setTampil] = useState(false);
return (
<div>
<button onClick={() => setTampil(!tampil)}>
{tampil ? "Sembunyikan" : "Tampilkan"}
</button>
{tampil && <p>Ini adalah teks rahasia! 🤫</p>}
</div>
);
}Challenge 3: Daftar Todo Sederhana
Buat component todo list:
- Input untuk ketik todo baru
- Tombol "Tambah" untuk menambahkan ke list
- Tampilkan semua todo dalam
<ul>
Hint: Butuh 2 state — satu untuk input text, satu untuk array todo.
💡 Hint
const [input, setInput] = useState("");
const [todos, setTodos] = useState([]);Untuk tambah: setTodos([...todos, input]) lalu setInput("")
✅ Solusi
import { useState } from 'react';
function TodoList() {
const [input, setInput] = useState("");
const [todos, setTodos] = useState([]);
function handleTambah() {
if (input.trim() === "") return; // Jangan tambah kalau kosong
setTodos([...todos, input]);
setInput(""); // Reset input
}
return (
<div>
<h2>Todo List</h2>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Tulis todo..."
/>
<button onClick={handleTambah}>Tambah</button>
<ul>
{todos.map((todo, index) => (
<li key={index}>{todo}</li>
))}
</ul>
<p>Total: {todos.length} todo</p>
</div>
);
}Challenge 4: Counter dengan Min/Max
Buat counter yang:
- Punya tombol +1 dan -1
- Tidak bisa kurang dari 0 (minimum)
- Tidak bisa lebih dari 10 (maximum)
- Tampilkan warning kalau sudah di batas
✅ Solusi
import { useState } from 'react';
function CounterMinMax() {
const [angka, setAngka] = useState(0);
const MIN = 0;
const MAX = 10;
function tambah() {
if (angka < MAX) setAngka(angka + 1);
}
function kurang() {
if (angka > MIN) setAngka(angka - 1);
}
return (
<div>
<h2>Counter: {angka}</h2>
<button onClick={kurang} disabled={angka <= MIN}>-1</button>
<button onClick={tambah} disabled={angka >= MAX}>+1</button>
{angka >= MAX && <p style={{ color: "red" }}>Sudah maksimum!</p>}
{angka <= MIN && <p style={{ color: "red" }}>Sudah minimum!</p>}
</div>
);
}Sudah paham materi ini?
Tandai sebagai selesai untuk melacak progress-mu.