ReactJS #17: React Router Part 2 – Menu dan Halaman Detail dari API


ReactJS #17: React Router Part 2

Membuat Menu dan Halaman Detail dari API

Halo, penjelajah rute! 🧭

Di artikel sebelumnya kita sudah belajar membuat navigasi antar halaman statis. Sekarang saatnya kita membuat aplikasi yang lebih dinamis: menampilkan daftar dari API, lalu setiap item bisa diklik untuk melihat detailnya. Ini adalah pola yang sangat umum di aplikasi web (misal: daftar berita, daftar produk, daftar postingan).

💡 Analogi: Bayangkan sebuah katalog perpustakaan. Halaman pertama menampilkan daftar judul buku (menu). Saat kamu klik salah satu judul, kamu dibawa ke halaman yang berisi detail buku tersebut (deskripsi, penulis, dll). React Router memungkinkan hal itu dengan sangat mudah!

📚 Apa yang Akan Kita Buat?

Kita akan membuat aplikasi sederhana dengan dua halaman:

  • Halaman Daftar Postingan – Mengambil data dari https://jsonplaceholder.typicode.com/posts dan menampilkan daftar judul. Setiap judul adalah link ke halaman detail.
  • Halaman Detail Postingan – Mengambil data detail postingan berdasarkan ID dari URL (misal: /post/1) menggunakan parameter rute. Menampilkan judul, isi, dan informasi penulis.

Kita juga akan belajar cara mengambil data di halaman detail berdasarkan parameter URL.

🧱 Langkah 1: Setup Router (Jika Belum)

Pastikan kamu sudah menginstal React Router di proyekmu:

npm install react-router-dom

Buat folder src/pages jika belum ada. Kita akan buat dua komponen halaman: PostList.js dan PostDetail.js.

📋 Langkah 2: Membuat Halaman Daftar Postingan

Buat file src/pages/PostList.js:

import { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; function PostList() { const [posts, setPosts] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { fetch('https://jsonplaceholder.typicode.com/posts') .then(res => { if (!res.ok) throw new Error('Gagal mengambil data'); return res.json(); }) .then(data => { setPosts(data); setLoading(false); }) .catch(err => { setError(err.message); setLoading(false); }); }, []); if (loading) { return ( < div classname="loading"> < div classname="spinner">< /div> < p>⏳ Memuat daftar postingan...< /p> < /div> ); } if (error) { return ( < div classname="loading" color:="" f44336=""> < p>😵 {error}< /p> < /div> ); } return ( < div> < h2>📰 Daftar Postingan< /h2> < p>Klik judul untuk melihat detail:< /p> < ul classname="post-list"> {posts.map(post => ( < li classname="post-item" key="{post.id}"> < link to="{`/post/${post.id}`}">< /link> < strong>{post.title}< /strong> < /li> ))} < /ul> < /div> ); } export default PostList;

Perhatikan: Link menggunakan path dinamis /post/${post.id}. Ini akan menghasilkan URL seperti /post/1, /post/2, dst.

🔍 Langkah 3: Membuat Halaman Detail Postingan

Buat file src/pages/PostDetail.js:

import { useState, useEffect } from 'react'; import { useParams, Link } from 'react-router-dom'; function PostDetail() { const { id } = useParams(); // mengambil parameter id dari URL const [post, setPost] = useState(null); const [author, setAuthor] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchData = async () => { setLoading(true); setError(null); try { // Ambil detail postingan const postRes = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`); if (!postRes.ok) throw new Error('Postingan tidak ditemukan'); const postData = await postRes.json(); setPost(postData); // Ambil data penulis (userId) const userRes = await fetch(`https://jsonplaceholder.typicode.com/users/${postData.userId}`); if (userRes.ok) { const userData = await userRes.json(); setAuthor(userData); } } catch (err) { setError(err.message); } finally { setLoading(false); } }; fetchData(); }, [id]); // dijalankan ulang jika id berubah if (loading) { return ( < div classname="loading"> < div classname="spinner">< /div> < p>⏳ Memuat detail...< /p> < /div> ); } if (error) { return ( < div classname="loading" color:="" f44336=""> < p>😵 {error}< /p> < /div> ); } return ( < div> < link classname="back-button" to="/">< /link>⬅️ Kembali ke Daftar < div classname="detail-card"> < h2>{post.title}< /h2> < p 1.6="" em="" fontsize:="" lineheight:="">{post.body}< /p> {author && ( < p> < strong>✍️ Penulis:< /strong> {author.name} ({author.email}) < /p> )} < p>< strong>📌 Postingan ID:< /strong> {post.id}< /p> < /div> < /div> ); } export default PostDetail;

Penjelasan:

  • useParams() – Hook dari React Router untuk mengambil parameter dari URL. Di sini kita mengambil id yang didefinisikan di path /post/:id.
  • Kita melakukan dua kali fetch: pertama untuk detail postingan, kedua untuk data penulis berdasarkan userId.
  • Dependency array [id] memastikan efek dijalankan ulang jika parameter berubah (misal dari /post/1 ke /post/2).
  • Tombol kembali menggunakan Link ke halaman utama.

⚙️ Langkah 4: Mengatur Rute di App.js

Sekarang kita atur routing di src/App.js:

import { BrowserRouter, Routes, Route, Link } from 'react-router-dom'; import PostList from './pages/PostList'; import PostDetail from './pages/PostDetail'; import './App.css'; function App() { return ( < browserrouter> < div classname="App"> < h1>📝 Aplikasi Postingan dengan Detail< /h1> {/* Menu sederhana */} < nav 0="" center="" margin:="" px="" textalign:=""> < link 15px="" em="" fontsize:="" margin:="" to="/">< /link>🏠 Daftar Postingan < /nav> < routes> < route element="{<PostList" path="/">} /> < route element="{<PostDetail" path="/post/:id">} /> < /route>< /route>< /routes> < /div> < /browserrouter> ); } export default App;

Perhatikan rute /post/:id. Tanda : menunjukkan bahwa id adalah parameter dinamis.

🎨 Langkah 5: Sedikit CSS (Opsional)

Tambahkan gaya di src/App.css atau di <style> untuk membuat tampilan lebih menarik. Beberapa gaya sudah kita tulis di dalam artikel ini, kamu bisa menyesuaikan.

🧪 Langkah 6: Uji Coba

Jalankan aplikasi dengan npm start. Coba:

  1. Halaman utama akan menampilkan daftar judul postingan.
  2. Klik salah satu judul. Kamu akan diarahkan ke halaman /post/1 (atau ID lainnya).
  3. Halaman detail akan menampilkan judul, isi, dan penulis (setelah mengambil data).
  4. Klik tombol "Kembali ke Daftar" untuk kembali ke halaman utama.
  5. Coba ketik langsung URL /post/999 (ID yang tidak ada). Seharusnya muncul error "Postingan tidak ditemukan".

🧩 Penjelasan Parameter URL

Parameter URL (atau route parameter) adalah bagian dari URL yang bisa berubah-ubah. Di React Router, kita mendefinisikannya dengan :namaParameter (misal :id). Nilai sesungguhnya bisa diambil dengan hook useParams().

Contoh:

  • /post/:id cocok dengan /post/5id = "5"
  • /user/:userId/post/:postId cocok dengan /user/3/post/10userId = "3", postId = "10"

⚠️ Hal Penting

  • Pastikan dependency array di useEffect berisi parameter ([id]) agar data diambil ulang saat parameter berubah.
  • Selalu tangani loading dan error di halaman detail juga.
  • Gunakan try/catch untuk menangani error async/await.

🧪 Latihan: Daftar Pengguna dan Detail

Coba buat fitur serupa untuk data pengguna dari https://jsonplaceholder.typicode.com/users:

  1. Halaman UserList menampilkan daftar nama (link ke detail).
  2. Halaman UserDetail dengan parameter /user/:id menampilkan nama, email, alamat, perusahaan, dll.
  3. Tambahkan link di menu untuk navigasi ke daftar pengguna.
💡 Tips: Kamu bisa membuat komponen LoadingSpinner terpisah agar tidak menulis kode spinner berulang-ulang. Atau gunakan skeleton seperti di artikel sebelumnya.

🚀 Kesimpulan

  • Parameter URL memungkinkan kita membuat halaman dinamis berdasarkan ID atau slug.
  • useParams() adalah hook untuk mengambil nilai parameter.
  • Kita bisa mengambil data dari API berdasarkan parameter tersebut di dalam useEffect.
  • Pola daftar-detail sangat umum dan bisa diterapkan untuk berbagai jenis data (postingan, produk, pengguna, dll).

Di artikel selanjutnya kita akan belajar tentang styling di React (CSS modules, styled components, atau Tailwind). Sampai jumpa!

Lebih baru Lebih lama

نموذج الاتصال