Tutorial React Dasar
Panduan lengkap mempelajari React dari nol untuk pemula
1. Pengenalan React
Apa itu React
React adalah library JavaScript untuk membangun antarmuka pengguna (UI) yang dikembangkan oleh Meta (Facebook).
Karakteristik React:
- Library berbasis komponen — UI dipecah menjadi bagian-bagian kecil
- Declarative — cukup deskripsikan tampilan, React yang urus perubahannya
- Virtual DOM — perubahan UI sangat efisien dan cepat
- One-way data flow — data mengalir dari parent ke child
- Open source dan sangat populer (dipakai Facebook, Instagram, Airbnb)
- Ekosistem besar dengan ribuan library pendukung
Mengapa Belajar React
- Library UI paling populer di dunia saat ini
- Permintaan kerja sangat tinggi di industri
- Dasar untuk mempelajari Next.js, React Native, dll.
- Komponen bisa dipakai ulang, hemat waktu development
- Komunitas besar, dokumentasi lengkap
- Mudah diintegrasikan dengan berbagai backend
- Cocok untuk SPA (Single Page Application)
React vs Vanilla JavaScript
VANILLA JAVASCRIPT:
// Update UI secara manual
const btn = document.getElementById('btn')
const counter = document.getElementById('counter')
let count = 0
btn.addEventListener('click', () => {
count++
counter.textContent = count // manipulasi DOM manual
})
--- vs ---
REACT:
// React urus DOM-nya sendiri
function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
)
}
KEUNTUNGAN REACT:
✓ Tidak perlu manipulasi DOM manual
✓ UI otomatis sinkron dengan data (state)
✓ Kode lebih terstruktur dan mudah dipelihara
✓ Komponen bisa dipakai ulang di mana saja
2. Requirements dan Setup
Requirements
- Node.js versi 18 atau lebih baru
- npm atau yarn sebagai package manager
- Pemahaman dasar HTML, CSS, JavaScript
- VS Code atau editor favorit lainnya
node --version
# Harusnya: v18.0.0 atau lebih baru
npm --version
# Harusnya: 8.x.x atau lebih baru
Membuat Proyek React Baru
# Cara modern (direkomendasikan) — Vite
npm create vite@latest nama-proyek -- --template react
# Masuk ke folder
cd nama-proyek
# Install dependencies
npm install
# Jalankan development server
npm run dev
# Buka browser: http://localhost:5173
---
# Cara lama — Create React App (CRA)
npx create-react-app nama-proyek
cd nama-proyek
npm start
# Buka browser: http://localhost:3000
Struktur Folder Proyek (Vite)
nama-proyek/
├── public/ ← File statis (favicon, dll)
├── src/ ← Kode sumber utama
│ ├── assets/ ← Gambar, font, dll
│ ├── components/ ← Komponen React (buat sendiri)
│ ├── App.jsx ← Komponen root utama
│ ├── App.css ← Style untuk App
│ ├── main.jsx ← Entry point aplikasi
│ └── index.css ← CSS global
├── index.html ← HTML template
├── package.json ← Dependencies
└── vite.config.js ← Konfigurasi Vite
File Pertama: main.jsx dan App.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
// Memasang komponen App ke dalam div#root di index.html
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>
)
function App() {
return (
<div>
<h1>Halo, React!</h1>
<p>Aplikasi React pertama saya.</p>
</div>
)
}
export default App
3. JSX
Apa itu JSX
JSX (JavaScript XML) adalah sintaks yang memungkinkan kita menulis HTML di dalam JavaScript. React mengubah JSX menjadi JavaScript biasa di balik layar.
// JSX terlihat seperti HTML, tapi ini JavaScript
function App() {
return (
<div>
<h1>Judul Halaman</h1>
<p>Paragraf pertama saya.</p>
</div>
)
}
// Di balik layar, JSX diubah menjadi:
function App() {
return React.createElement('div', null,
React.createElement('h1', null, 'Judul Halaman'),
React.createElement('p', null, 'Paragraf pertama saya.')
)
}
// Makanya lebih enak pakai JSX!
Aturan Penting JSX
// 1. Harus ada satu elemen pembungkus (root element)
// SALAH:
return (
<h1>Judul</h1>
<p>Paragraf</p>
)
// BENAR: pakai div atau Fragment
return (
<div>
<h1>Judul</h1>
<p>Paragraf</p>
</div>
)
// BENAR: pakai Fragment (tidak tambah elemen ke DOM)
return (
<>
<h1>Judul</h1>
<p>Paragraf</p>
</>
)
// 2. class → className (karena 'class' kata kunci JS)
<div className="container">...</div>
// 3. Tag harus selalu ditutup
<input type="text" /> // BENAR
<br /> // BENAR
<img src="foto.jpg" /> // BENAR
// 4. Ekspresi JavaScript pakai kurung kurawal {}
const nama = "Ahmad"
return <h1>Halo, {nama}!</h1>
return <p>1 + 1 = {1 + 1}</p>
return <p>{new Date().getFullYear()}</p>
Ekspresi dalam JSX
function Profil() {
const nama = "Ahmad"
const umur = 20
const aktif = true
const hobi = ["Coding", "Gaming", "Membaca"]
return (
<div>
{/* Variabel */}
<p>Nama: {nama}</p>
<p>Umur: {umur} tahun</p>
{/* Operasi */}
<p>Lahir tahun: {2025 - umur}</p>
{/* Conditional rendering */}
<p>Status: {aktif ? "Aktif" : "Tidak Aktif"}</p>
{/* Conditional show/hide */}
{aktif && <span>🟢 Online</span>}
{/* Render list */}
<ul>
{hobi.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
)
}
4. Komponen
Membuat Komponen
Komponen adalah blok bangunan React. Setiap komponen adalah sebuah fungsi JavaScript yang mengembalikan JSX.
// Aturan: nama komponen HARUS diawali huruf kapital
function Greeting() {
return (
<div>
<h2>Selamat Datang!</h2>
<p>Ini adalah komponen React pertama saya.</p>
</div>
)
}
export default Greeting
// Cara penggunaan di App.jsx:
import Greeting from './components/Greeting'
function App() {
return (
<div>
<Greeting /> {/* Komponen dipanggil seperti tag HTML */}
<Greeting /> {/* Bisa dipakai berulang kali! */}
</div>
)
}
Komponen dengan Style
// 1. Inline style (pakai object, bukan string)
function Card() {
const style = {
background: 'white',
padding: '20px',
borderRadius: '8px',
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
}
return <div style={style}>Isi kartu</div>
}
// 2. CSS file biasa
// Card.css:
// .card { background: white; padding: 20px; }
import './Card.css'
function Card() {
return <div className="card">Isi kartu</div>
}
// 3. CSS Modules (class bersifat lokal)
import styles from './Card.module.css'
function Card() {
return <div className={styles.card}>Isi kartu</div>
}
Komposisi Komponen
// Komponen kecil-kecil digabung jadi satu halaman
function Header() {
return <header><h1>Logo Saya</h1></header>
}
function Sidebar() {
return <aside><p>Menu navigasi</p></aside>
}
function Content() {
return <main><p>Konten utama</p></main>
}
function Footer() {
return <footer><p>© 2025</p></footer>
}
// Digabung di App
function App() {
return (
<div>
<Header />
<div style={{ display: 'flex' }}>
<Sidebar />
<Content />
</div>
<Footer />
</div>
)
}
5. Props
Pengenalan Props
Props (properties) adalah cara mengirim data dari komponen parent ke komponen child. Props bersifat read-only — child tidak boleh mengubah props yang diterima.
// Komponen menerima props sebagai parameter
function Greeting(props) {
return <h1>Halo, {props.nama}!</h1>
}
// Lebih rapi dengan destructuring
function Greeting({ nama }) {
return <h1>Halo, {nama}!</h1>
}
// Penggunaan — kirim data via atribut
function App() {
return (
<div>
<Greeting nama="Ahmad" />
<Greeting nama="Budi" />
<Greeting nama="Citra" />
</div>
)
}
Berbagai Jenis Props
function ProfilKartu({ nama, umur, aktif, hobi, onClick }) {
return (
<div>
<p>Nama: {nama}</p> {/* String */}
<p>Umur: {umur} tahun</p> {/* Number */}
<p>Aktif: {aktif ? 'Ya' : 'Tidak'}</p> {/* Boolean */}
<ul>
{hobi.map((h, i) => <li key={i}>{h}</li>)} {/* Array */}
</ul>
<button onClick={onClick}>Klik Saya</button> {/* Function */}
</div>
)
}
// Penggunaan:
function App() {
const handleKlik = () => alert('Kartu diklik!')
return (
<ProfilKartu
nama="Ahmad"
umur={20}
aktif={true}
hobi={["Coding", "Gaming"]}
onClick={handleKlik}
/>
)
}
Default Props dan Children
// Default props — nilai default jika tidak dikirim
function Tombol({ label = "Klik", warna = "black", onClick }) {
return (
<button
onClick={onClick}
style={{ background: warna, color: 'white', padding: '8px 16px' }}
>
{label}
</button>
)
}
<Tombol /> {/* Klik, hitam */}
<Tombol label="Simpan" /> {/* Simpan, hitam */}
<Tombol label="Hapus" warna="red" /> {/* Hapus, merah */}
---
// Props children — konten yang disisipkan ke dalam komponen
function Kartu({ children }) {
return (
<div style={{ border: '1px solid #ccc', padding: '20px', borderRadius: '8px' }}>
{children}
</div>
)
}
// Penggunaan:
<Kartu>
<h2>Judul Kartu</h2>
<p>Isi kartu bisa apa saja.</p>
</Kartu>
6. State dengan useState
Pengenalan State
State adalah data yang bisa berubah di dalam komponen. Saat state berubah, React otomatis me-render ulang komponen dengan tampilan terbaru.
import { useState } from 'react'
function Counter() {
// useState(nilai awal) → [nilai saat ini, fungsi untuk update]
const [count, setCount] = useState(0)
return (
<div>
<p>Hitungan: {count}</p>
<button onClick={() => setCount(count + 1)}>Tambah</button>
<button onClick={() => setCount(count - 1)}>Kurang</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
)
}
// ATURAN PENTING:
// Jangan ubah state langsung → count++ ← SALAH
// Selalu pakai fungsi setter → setCount(count + 1) ← BENAR
State dengan String dan Boolean
import { useState } from 'react'
function FormSederhana() {
const [nama, setNama] = useState('')
const [tampilkan, setTampilkan] = useState(false)
return (
<div>
<input
type="text"
value={nama}
onChange={(e) => setNama(e.target.value)}
placeholder="Masukkan nama..."
/>
<button onClick={() => setTampilkan(!tampilkan)}>
{tampilkan ? 'Sembunyikan' : 'Tampilkan'}
</button>
{tampilkan && <p>Halo, {nama || 'Teman'}!</p>}
</div>
)
}
State dengan Object dan Array
import { useState } from 'react'
function FormProfil() {
// State berupa object
const [profil, setProfil] = useState({ nama: '', email: '' })
const handleChange = (e) => {
setProfil({
...profil, // spread dulu nilai lama
[e.target.name]: e.target.value // baru update field-nya
})
}
return (
<form>
<input name="nama" value={profil.nama} onChange={handleChange} placeholder="Nama" />
<input name="email" value={profil.email} onChange={handleChange} placeholder="Email" />
<p>Preview: {profil.nama} — {profil.email}</p>
</form>
)
}
---
function TodoList() {
// State berupa array
const [todos, setTodos] = useState(['Belajar React', 'Buat project'])
const [input, setInput] = useState('')
const tambah = () => {
setTodos([...todos, input]) // spread array lama, tambah item baru
setInput('')
}
const hapus = (index) => {
setTodos(todos.filter((_, i) => i !== index))
}
return (
<div>
<input value={input} onChange={e => setInput(e.target.value)} />
<button onClick={tambah}>Tambah</button>
<ul>
{todos.map((todo, i) => (
<li key={i}>
{todo} <button onClick={() => hapus(i)}>Hapus</button>
</li>
))}
</ul>
</div>
)
}
7. Hooks Penting
useState
Menyimpan dan mengubah data dalam komponen
useEffect
Menjalankan efek samping: fetch data, timer, subscribe
useRef
Akses elemen DOM langsung atau simpan nilai tanpa re-render
useContext
Berbagi data ke banyak komponen tanpa props drilling
useEffect
import { useState, useEffect } from 'react'
function DataPengguna() {
const [users, setUsers] = useState([])
const [loading, setLoading] = useState(true)
// useEffect(fungsi, dependency array)
useEffect(() => {
// Jalankan saat komponen pertama kali muncul
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => res.json())
.then(data => {
setUsers(data)
setLoading(false)
})
}, []) // [] → hanya jalankan sekali saat mount
if (loading) return <p>Memuat data...</p>
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name} — {user.email}</li>
))}
</ul>
)
}
// Variasi dependency array:
useEffect(() => { /* ... */ }) // Setiap re-render
useEffect(() => { /* ... */ }, []) // Hanya sekali (mount)
useEffect(() => { /* ... */ }, [id]) // Setiap 'id' berubah
// Cleanup function (penting untuk timer, subscription)
useEffect(() => {
const timer = setInterval(() => console.log('tick'), 1000)
return () => clearInterval(timer) // Bersihkan saat unmount
}, [])
useRef
import { useRef } from 'react'
function FormFokus() {
const inputRef = useRef(null)
const handleKlik = () => {
inputRef.current.focus() // Fokus ke input secara langsung
}
return (
<div>
<input ref={inputRef} type="text" placeholder="Klik tombol di bawah..." />
<button onClick={handleKlik}>Fokus ke Input</button>
</div>
)
}
---
// useRef untuk menyimpan nilai tanpa trigger re-render
import { useState, useRef, useEffect } from 'react'
function Timer() {
const [detik, setDetik] = useState(0)
const intervalRef = useRef(null)
const mulai = () => {
intervalRef.current = setInterval(() => {
setDetik(prev => prev + 1)
}, 1000)
}
const berhenti = () => {
clearInterval(intervalRef.current)
}
return (
<div>
<p>{detik} detik</p>
<button onClick={mulai}>Mulai</button>
<button onClick={berhenti}>Berhenti</button>
</div>
)
}
useContext
import { createContext, useContext, useState } from 'react'
// 1. Buat context
const TemaContext = createContext()
// 2. Buat provider (pembungkus)
function TemaProvider({ children }) {
const [tema, setTema] = useState('terang')
const toggleTema = () => {
setTema(prev => prev === 'terang' ? 'gelap' : 'terang')
}
return (
<TemaContext.Provider value={{ tema, toggleTema }}>
{children}
</TemaContext.Provider>
)
}
// 3. Gunakan di komponen manapun
function TombolTema() {
const { tema, toggleTema } = useContext(TemaContext)
return (
<button onClick={toggleTema}>
Tema sekarang: {tema}
</button>
)
}
// 4. Bungkus App dengan Provider
function App() {
return (
<TemaProvider>
<TombolTema />
</TemaProvider>
)
}
8. Event Handling
Event Dasar
function KomponenEvent() {
// Handler sebagai fungsi terpisah
const handleKlik = () => {
alert('Tombol diklik!')
}
const handleHover = () => {
console.log('Mouse di atas elemen')
}
return (
<div>
<button onClick={handleKlik}>Klik Saya</button>
<div onMouseEnter={handleHover}>Hover di sini</div>
</div>
)
}
// Event umum di React:
// onClick → klik mouse
// onChange → perubahan input
// onSubmit → submit form
// onMouseEnter → mouse masuk area
// onMouseLeave → mouse keluar area
// onKeyDown → tombol keyboard ditekan
// onFocus → elemen mendapat fokus
// onBlur → elemen kehilangan fokus
Event Object dan Form
import { useState } from 'react'
function FormLogin() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [pesan, setPesan] = useState('')
// e = event object
const handleSubmit = (e) => {
e.preventDefault() // Cegah reload halaman
if (!email || !password) {
setPesan('Email dan password harus diisi!')
return
}
setPesan(`Login dengan: ${email}`)
}
return (
<form onSubmit={handleSubmit}>
<div>
<label>Email:</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="email@contoh.com"
/>
</div>
<div>
<label>Password:</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<button type="submit">Login</button>
{pesan && <p>{pesan}</p>}
</form>
)
}
Kirim Argumen ke Handler
function DaftarProduk() {
const produk = [
{ id: 1, nama: 'Laptop', harga: 8000000 },
{ id: 2, nama: 'Mouse', harga: 150000 },
{ id: 3, nama: 'Keyboard', harga: 300000 },
]
// Kirim argumen melalui arrow function
const handleBeli = (id, nama) => {
alert(`Membeli: ${nama} (ID: ${id})`)
}
const handleHapus = (id) => {
console.log('Hapus produk ID:', id)
}
return (
<ul>
{produk.map(item => (
<li key={item.id}>
{item.nama} — Rp {item.harga.toLocaleString()}
<button onClick={() => handleBeli(item.id, item.nama)}>
Beli
</button>
<button onClick={() => handleHapus(item.id)}>
Hapus
</button>
</li>
))}
</ul>
)
}
9. List dan Conditional Rendering
Render List dengan map()
function DaftarSiswa() {
const siswa = [
{ id: 1, nama: 'Ahmad', nilai: 90 },
{ id: 2, nama: 'Budi', nilai: 85 },
{ id: 3, nama: 'Citra', nilai: 92 },
]
return (
<table>
<thead>
<tr><th>Nama</th><th>Nilai</th></tr>
</thead>
<tbody>
{siswa.map(s => (
// key WAJIB ada — harus unik di antara sibling
<tr key={s.id}>
<td>{s.nama}</td>
<td>{s.nilai}</td>
</tr>
))}
</tbody>
</table>
)
}
// PENTING: Key harus unik dan stabil
// BENAR: key={item.id} (pakai ID dari data)
// HINDARI: key={index} (index bisa berubah saat list diurutkan/dihapus)
Conditional Rendering
function StatusLogin({ isLogin, nama }) {
// 1. if/else biasa
if (!isLogin) {
return <p>Silakan login terlebih dahulu.</p>
}
// 2. Ternary operator (inline)
return (
<div>
{isLogin ? (
<p>Selamat datang, {nama}!</p>
) : (
<p>Kamu belum login.</p>
)}
{/* 3. Short-circuit && (tampilkan atau tidak sama sekali) */}
{isLogin && <button>Logout</button>}
{!isLogin && <button>Login</button>}
</div>
)
}
---
// Contoh nyata: loading state
function Artikel({ id }) {
const [data, setData] = useState(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
useEffect(() => {
fetch(`/api/artikel/${id}`)
.then(r => r.json())
.then(d => { setData(d); setLoading(false) })
.catch(e => { setError(e.message); setLoading(false) })
}, [id])
if (loading) return <p>Memuat artikel...</p>
if (error) return <p>Error: {error}</p>
if (!data) return <p>Artikel tidak ditemukan.</p>
return (
<article>
<h1>{data.judul}</h1>
<p>{data.isi}</p>
</article>
)
}
Filter dan Sort List
import { useState } from 'react'
function DaftarProduk() {
const [filter, setFilter] = useState('')
const [urutkan, setUrutkan] = useState('nama')
const produk = [
{ id: 1, nama: 'Laptop', kategori: 'Elektronik', harga: 8000000 },
{ id: 2, nama: 'Buku React', kategori: 'Buku', harga: 150000 },
{ id: 3, nama: 'Mouse', kategori: 'Elektronik', harga: 200000 },
{ id: 4, nama: 'Buku Python', kategori: 'Buku', harga: 120000 },
]
const tampil = produk
.filter(p => filter === '' || p.kategori === filter)
.sort((a, b) => a[urutkan] > b[urutkan] ? 1 : -1)
return (
<div>
<select onChange={e => setFilter(e.target.value)}>
<option value="">Semua Kategori</option>
<option value="Elektronik">Elektronik</option>
<option value="Buku">Buku</option>
</select>
<select onChange={e => setUrutkan(e.target.value)}>
<option value="nama">Urutkan: Nama</option>
<option value="harga">Urutkan: Harga</option>
</select>
<ul>
{tampil.map(p => (
<li key={p.id}>{p.nama} — Rp {p.harga.toLocaleString()}</li>
))}
</ul>
</div>
)
}
Kesimpulan dan Langkah Berikutnya
Ringkasan Materi
- Pengenalan React dan perbedaannya dengan Vanilla JS
- Setup proyek dengan Vite + React
- JSX — sintaks HTML dalam JavaScript
- Komponen — blok bangunan UI React
- Props — mengirim data dari parent ke child
- State dengan useState — data yang bisa berubah
- Hooks penting: useEffect, useRef, useContext
- Event handling dan form
- Render list, key, dan conditional rendering
Langkah Selanjutnya
Topik lanjutan untuk memperdalam React:
- React Router — navigasi antar halaman di SPA
- useReducer — state management yang lebih kompleks
- Custom Hooks — membuat hook sendiri yang reusable
- useMemo & useCallback — optimasi performa
- React Query / SWR — data fetching yang lebih canggih
- Zustand / Redux — global state management
- TypeScript + React — type safety
- Testing — React Testing Library, Vitest
- Next.js — React framework untuk production
- React Native — mobile app dengan React
Tips Belajar
- Buat mini project: counter, todo list, kalkulator
- Pahami benar kapan pakai state vs props
- Jangan takut error — baca pesan error dengan teliti
- Gunakan React DevTools di browser untuk debug
- Latihan memecah UI menjadi komponen kecil-kecil
- Ikuti tutorial build project nyata di YouTube
- Baca dokumentasi resmi React — sangat lengkap
- Push semua project ke GitHub sebagai portofolio
Resources Berguna
Dokumentasi Resmi React (sangat bagus!):
https://react.dev
React Tutorial Interaktif:
https://react.dev/learn
Vite (build tool):
https://vitejs.dev
React Router:
https://reactrouter.com
Tailwind CSS:
https://tailwindcss.com
Stack Overflow (Q&A):
https://stackoverflow.com (tag: reactjs)