Tutorial React Router untuk Pemula
Pendahuluan
Bayangkan kamu sedang membangun aplikasi web seperti Tokopedia — ada halaman beranda, halaman detail produk, halaman keranjang, dan halaman profil. Tanpa sistem navigasi yang baik, pengguna tidak bisa berpindah antar halaman tersebut dengan mudah.
Di sinilah React Router berperan. React Router adalah library navigasi paling populer untuk React yang memungkinkan kamu membuat aplikasi multi-halaman (SPA — Single Page Application) tanpa harus reload browser setiap kali berpindah halaman.
Sebelum masuk ke React Router, pastikan kamu sudah familiar dengan dasar-dasar React. Jika belum, kamu bisa mempelajari Panduan Lengkap Tipe Data dan Operator JavaScript sebagai fondasi yang kuat.
Instalasi dan Setup Awal
Pertama, buat project React baru atau gunakan project yang sudah ada. Kemudian install React Router:
# Buat project baru dengan Vite
npm create vite@latest my-app -- --template react
cd my-app
npm install
# Install React Router v6
npm install react-router-dom
Setelah instalasi, struktur folder project kamu akan terlihat seperti ini:
src/
├── components/
│ └── Navbar.jsx
├── pages/
│ ├── Home.jsx
│ ├── About.jsx
│ ├── Contact.jsx
│ └── NotFound.jsx
├── App.jsx
└── main.jsx
Konsep Inti: BrowserRouter, Routes, Route, dan Link
React Router punya beberapa komponen utama yang perlu kamu pahami. Analoginya seperti sistem jalan raya: BrowserRouter adalah seluruh jaringan jalan, Routes adalah persimpangan besar, Route adalah jalan menuju destinasi tertentu, dan Link adalah kendaraan yang membawamu ke sana.
BrowserRouter
Bungkus seluruh aplikasi dengan BrowserRouter di file main.jsx:
// main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter>
<App />
</BrowserRouter>
)
Routes dan Route
Definisikan semua rute di App.jsx. Buat juga file untuk setiap halaman terlebih dahulu:
// pages/Home.jsx
function Home() {
return (
<div>
<h1>Selamat Datang di Blog Kami</h1>
<p>Temukan artikel menarik seputar pemrograman di sini.</p>
</div>
)
}
export default Home
// pages/About.jsx
function About() {
return (
<div>
<h1>Tentang Kami</h1>
<p>Kami adalah komunitas developer yang berbagi ilmu pemrograman dalam Bahasa Indonesia.</p>
</div>
)
}
export default About
// pages/Contact.jsx
function Contact() {
return (
<div>
<h1>Hubungi Kami</h1>
<p>Kirim pertanyaan atau saran kamu melalui email: [email protected]</p>
</div>
)
}
export default Contact
// pages/NotFound.jsx
import { Link } from 'react-router-dom'
function NotFound() {
return (
<div>
<h1>404 — Halaman Tidak Ditemukan</h1>
<p>Maaf, halaman yang kamu cari tidak ada.</p>
<Link to="/">Kembali ke Beranda</Link>
</div>
)
}
export default NotFound
Sekarang definisikan semua rute di App.jsx:
// App.jsx
import { Routes, Route } from 'react-router-dom'
import Navbar from './components/Navbar'
import Home from './pages/Home'
import About from './pages/About'
import Contact from './pages/Contact'
import NotFound from './pages/NotFound'
function App() {
return (
<>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="*" element={<NotFound />} />
</Routes>
</>
)
}
export default App
Link
Gunakan Link untuk navigasi — jangan gunakan tag <a> biasa karena akan menyebabkan full page reload:
// components/Navbar.jsx
import { Link } from 'react-router-dom'
function Navbar() {
return (
<nav style={{ display: 'flex', gap: '1rem', padding: '1rem', background: '#f0f0f0' }}>
<Link to="/">Beranda</Link>
<Link to="/about">Tentang</Link>
<Link to="/contact">Kontak</Link>
</nav>
)
}
export default Navbar
Membuat Rute Dinamis dengan Parameter
Bayangkan kamu membangun halaman detail artikel seperti di blog. Setiap artikel punya URL unik seperti /artikel/react-router atau /artikel/belajar-hooks. Kamu tidak mungkin membuat Route terpisah untuk setiap artikel — di sinilah parameter rute berguna.
// App.jsx — tambahkan route dinamis
<Routes>
<Route path="/" element={<Home />} />
<Route path="/artikel/:slug" element={<DetailArtikel />} />
<Route path="*" element={<NotFound />} />
</Routes>
Tanda :slug adalah parameter dinamis. Untuk mengambil nilainya di dalam komponen, gunakan hook useParams:
// pages/DetailArtikel.jsx
import { useParams, useNavigate } from 'react-router-dom'
function DetailArtikel() {
const { slug } = useParams()
const navigate = useNavigate()
return (
<div>
<button onClick={() => navigate(-1)}>← Kembali</button>
<h1>Membaca artikel: {slug}</h1>
<p>Konten artikel berdasarkan slug akan dimuat di sini.</p>
</div>
)
}
export default DetailArtikel
Saat pengguna mengunjungi /artikel/react-router, nilai slug akan menjadi "react-router". Kamu bisa gunakan nilai ini untuk fetch data dari API.
Rute Bersarang (Nested Routes) dan Outlet
Nested Routes berguna saat kamu punya layout bersama untuk beberapa halaman. Misalnya, halaman dashboard yang memiliki sidebar konsisten, tetapi konten utamanya berubah.
// App.jsx
import Dashboard from './pages/Dashboard'
import Profil from './pages/Profil'
import Pengaturan from './pages/Pengaturan'
<Routes>
<Route path="/dashboard" element={<Dashboard />}>
<Route path="profil" element={<Profil />} />
<Route path="pengaturan" element={<Pengaturan />} />
</Route>
</Routes>
Buat komponen halaman untuk nested routes:
// pages/Profil.jsx
function Profil() {
return (
<div>
<h2>Profil Saya</h2>
<p>Nama: Budi Santoso</p>
<p>Email: [email protected]</p>
</div>
)
}
export default Profil
// pages/Pengaturan.jsx
function Pengaturan() {
return (
<div>
<h2>Pengaturan</h2>
<p>Kelola preferensi akun kamu di sini.</p>
</div>
)
}
export default Pengaturan
Di komponen Dashboard, gunakan <Outlet /> sebagai tempat “placeholder” di mana komponen child akan dirender:
// pages/Dashboard.jsx
import { Outlet, Link } from 'react-router-dom'
function Dashboard() {
return (
<div style={{ display: 'flex', gap: '2rem', padding: '1rem' }}>
<aside>
<h2>Dashboard</h2>
<nav style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
<Link to="profil">Profil Saya</Link>
<Link to="pengaturan">Pengaturan</Link>
</nav>
</aside>
<main style={{ flex: 1 }}>
{/* Komponen child akan muncul di sini */}
<Outlet />
</main>
</div>
)
}
export default Dashboard
Saat pengguna mengunjungi /dashboard/profil, komponen Profil akan dirender di dalam <Outlet /> sambil sidebar tetap tampil.
Navigasi Terprogram dengan useNavigate
Terkadang kamu perlu berpindah halaman bukan karena klik link, tapi karena suatu kondisi — misalnya setelah login berhasil, redirect ke dashboard. Gunakan hook useNavigate:
// pages/Login.jsx
import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
function Login() {
const [email, setEmail] = useState('')
const navigate = useNavigate()
const handleLogin = (e) => {
e.preventDefault()
// Simulasi proses login berhasil
if (email === '[email protected]') {
navigate('/dashboard') // Redirect ke dashboard
} else {
navigate('/login?error=1') // Redirect dengan query string
}
}
return (
<form onSubmit={handleLogin}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<button type="submit">Login</button>
</form>
)
}
export default Login
Kamu juga bisa navigasi mundur seperti tombol Back browser:
navigate(-1) // Kembali ke halaman sebelumnya
navigate(-2) // Kembali 2 halaman
Contoh Kasus Nyata: Membuat Aplikasi Blog Sederhana
Mari gabungkan semua konsep di atas dalam contoh blog mini. Jika kamu ingin membangun platform konten seperti Medium atau Kaskus, pola ini sangat relevan.
// App.jsx — Struktur lengkap blog sederhana
import { Routes, Route } from 'react-router-dom'
import Navbar from './components/Navbar'
import Home from './pages/Home'
import DaftarArtikel from './pages/DaftarArtikel'
import DetailArtikel from './pages/DetailArtikel'
import NotFound from './pages/NotFound'
const articles = [
{ id: 1, slug: 'belajar-react', title: 'Belajar React', content: 'React adalah library UI yang dikembangkan oleh Meta untuk membangun antarmuka yang interaktif.' },
{ id: 2, slug: 'react-hooks', title: 'React Hooks', content: 'Hooks memudahkan manajemen state dan side effects tanpa perlu class component.' },
{ id: 3, slug: 'react-router', title: 'React Router', content: 'React Router memungkinkan navigasi multi-halaman dalam aplikasi SPA.' },
]
function App() {
return (
<>
<Navbar />
<div style={{ padding: '1rem' }}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/artikel" element={<DaftarArtikel articles={articles} />} />
<Route path="/artikel/:slug" element={<DetailArtikel articles={articles} />} />
<Route path="*" element={<NotFound />} />
</Routes>
</div>
</>
)
}
export default App
// pages/Home.jsx
import { Link } from 'react-router-dom'
function Home() {
return (
<div>
<h1>Selamat Datang di Blog React</h1>
<p>Pelajari React dari dasar hingga mahir bersama kami.</p>
<Link to="/artikel">Lihat Semua Artikel →</Link>
</div>
)
}
export default Home
// pages/DaftarArtikel.jsx
import { Link } from 'react-router-dom'
function DaftarArtikel({ articles }) {
return (
<div>
<h1>Semua Artikel</h1>
{articles.map((article) => (
<div key={article.id} style={{ marginBottom: '1rem', padding: '1rem', border: '1px solid #ccc' }}>
<h2>
<Link to={`/artikel/${article.slug}`}>{article.title}</Link>
</h2>
<p>{article.content.substring(0, 80)}...</p>
</div>
))}
</div>
)
}
export default DaftarArtikel
// pages/DetailArtikel.jsx
import { useParams, useNavigate } from 'react-router-dom'
function DetailArtikel({ articles }) {
const { slug } = useParams()
const navigate = useNavigate()
const article = articles.find((a) => a.slug === slug)
if (!article) {
return (
<div>
<p>Artikel tidak ditemukan.</p>
<button onClick={() => navigate('/artikel')}>← Kembali ke Daftar</button>
</div>
)
}
return (
<div>
<button onClick={() => navigate(-1)}>← Kembali</button>
<h1>{article.title}</h1>
<p>{article.content}</p>
</div>
)
}
export default DetailArtikel
// pages/NotFound.jsx
import { Link } from 'react-router-dom'
function NotFound() {
return (
<div style={{ textAlign: 'center', padding: '3rem' }}>
<h1>404 — Halaman Tidak Ditemukan</h1>
<p>Maaf, halaman yang kamu cari tidak ada.</p>
<Link to="/">← Kembali ke Beranda</Link>
</div>
)
}
export default NotFound
Perhatikan route path="*" — ini adalah catch-all route yang akan menangkap semua URL yang tidak cocok dengan route manapun, sempurna untuk halaman 404.
Troubleshooting: Error yang Sering Muncul
useNavigate() may be used only in the context of a Router component
Penyebab: Kamu memanggil hook useNavigate (atau hook React Router lainnya) di dalam komponen yang berada di luar BrowserRouter.
Solusi:
// ❌ Salah — App berada di luar BrowserRouter
ReactDOM.createRoot(document.getElementById('root')).render(
<App />
)
// ✅ Benar — BrowserRouter membungkus seluruh App
ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter>
<App />
</BrowserRouter>
)
No routes matched location ”/”
Penyebab: Komponen Routes tidak memiliki Route yang cocok dengan path yang diminta, atau kamu lupa menambahkan Routes sebagai wrapper.
Solusi:
// ❌ Salah — Route tanpa dibungkus Routes
<Route path="/" element={<Home />} />
// ✅ Benar — Route harus berada di dalam Routes
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
Halaman menjadi blank saat refresh di Netlify/Vercel
Penyebab: Server hosting tidak tahu cara menangani URL dinamis seperti /artikel/react-router karena file tersebut tidak ada secara fisik — React Router menangani routing di sisi client.
Solusi:
# Untuk Netlify — buat file public/_redirects
/* /index.html 200
// Untuk Vite — tambahkan di vite.config.js
export default {
server: {
historyApiFallback: true,
}
}
Warning: Each child in a list should have a unique “key” prop saat render Link
Penyebab: Saat merender daftar Link dari array, kamu lupa menambahkan prop key yang unik.
Solusi:
// ❌ Salah — tidak ada key
{articles.map((article) => (
<Link to={`/artikel/${article.slug}`}>{article.title}</Link>
))}
// ✅ Benar — tambahkan key yang unik
{articles.map((article) => (
<Link key={article.id} to={`/artikel/${article.slug}`}>{article.title}</Link>
))}
Pertanyaan yang Sering Diajukan
Apa itu React Router dan mengapa harus menggunakannya?
React Router adalah library untuk mengelola navigasi di aplikasi React. Tanpanya, kamu hanya bisa membuat SPA satu halaman. Dengan React Router, kamu bisa membuat URL yang bermakna (/produk/sepatu), mendukung tombol Back/Forward browser, dan membagi kode menjadi halaman-halaman yang terpisah sehingga aplikasi lebih mudah dikelola.
Apa perbedaan antara Link dan <a> biasa di React?
Tag <a> biasa akan melakukan full page reload yang menghancurkan state React dan memperlambat navigasi. Sedangkan Link dari React Router hanya mengupdate URL dan merender ulang komponen yang diperlukan tanpa reload, membuat navigasi terasa instan seperti aplikasi native.
Bagaimana cara membuat halaman 404 di React Router?
Gunakan wildcard path="*" sebagai Route terakhir di dalam Routes. Route ini akan cocok dengan URL apapun yang tidak tertangkap oleh route sebelumnya:
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<NotFound />} />
</Routes>
Bagaimana cara mengirim data antar halaman saat navigasi?
Gunakan state pada navigate() atau Link. Data ini bisa diakses dengan hook useLocation:
// Mengirim data saat navigasi
navigate('/detail', { state: { id: 123, nama: 'Produk A' } })
// Menerima data di halaman tujuan
import { useLocation } from 'react-router-dom'
function Detail() {
const location = useLocation()
console.log(location.state.nama) // "Produk A"
return <h1>{location.state.nama}</h1>
}
Apakah React Router bisa digunakan bersama TypeScript?
Tentu saja! React Router memiliki dukungan TypeScript yang sangat baik. Jika kamu ingin mengembangkan aplikasi React yang lebih robust, pelajari Pengenalan TypeScript: Superset JavaScript yang Lebih Aman untuk memahami bagaimana TypeScript dapat membantu kamu menulis kode navigasi yang lebih aman dan terstruktur.
Kesimpulan
React Router adalah fondasi penting untuk membangun aplikasi React yang lebih dari sekedar satu halaman. Kamu sudah belajar cara menginstal dan setup BrowserRouter, mendefinisikan rute dengan Routes dan Route, membuat navigasi dengan Link, menggunakan parameter dinamis dengan useParams, membangun nested routes dengan Outlet, dan melakukan navigasi terprogram dengan useNavigate.
Langkah selanjutnya, coba eksplorasi fitur lebih lanjut seperti lazy loading untuk memuat halaman secara on-demand, atau Protected Routes untuk membatasi akses halaman hanya bagi pengguna yang sudah login — pola yang sangat umum digunakan di aplikasi seperti Gojek atau Tokopedia.
Selamat belajar dan terus berlatih! Jangan ragu untuk bereksperimen dengan contoh-contoh di atas, dan jika ada pertanyaan, kunjungi artikel-artikel lain di KamusNgoding untuk memperdalam pemahamanmu.