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 DOM | React menggunakan virtual DOM untuk memperbarui UI secara efisien tanpa merender ulang seluruh halaman |
| Komponen Reusable | Setiap komponen bisa digunakan kembali di berbagai bagian aplikasi |
| Ekosistem Besar | Ribuan library pendukung seperti React Router, Redux, Next.js, dll. |
| Declarative | Cukup deskripsikan apa yang ingin ditampilkan, React menangani DOM-nya |
| React Native | Skill React bisa langsung dipakai untuk membuat aplikasi mobile |
| Komunitas Aktif | Dokumentasi lengkap, tutorial berlimpah, dan dukungan komunitas global |
React vs Framework Lain
| Aspek | React | Vue.js | Angular |
|---|---|---|---|
| Tipe | Library | Framework | Framework |
| Bahasa | JavaScript/JSX | JavaScript/Template | TypeScript |
| Ukuran | ~42 KB (gzip) | ~33 KB (gzip) | ~143 KB (gzip) |
| Learning Curve | π‘ Sedang | π’ Mudah | π΄ Curam |
| State Management | useState / Redux / Zustand | Vuex / Pinia | NgRx / Services |
| Cocok untuk | SPA, Mobile App, Dashboard | SPA kecil-sedang | Enterprise App |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β 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:
# 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
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
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 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>
</>
);
}
JSX memiliki beberapa perbedaan penting dari HTML biasa:
classmenjadiclassNameformenjadihtmlFor- Gunakan camelCase untuk atribut:
onclickβonClick - Semua tag harus ditutup:
<img />,<input /> - Ekspresi JavaScript dimasukkan dengan
{ }bukan{{ }}
Embedding Expressions dalam JSX
// 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
// 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.
// 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>
);
}
ββββββββββββββββββββββββββββββββββββββββββββ β 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
// 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 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)
// 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.
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.
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.
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>
);
}
| Dependency Array | Kapan 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.
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.
// 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.
// 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>
);
}
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.
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;
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: