Dynamic маршрут ба params
Жинхэнэ вэбсайтад бүтээгдэхүүн бүр, нийтлэл бүр, хэрэглэгч бүр өөрийн хуудастай байдаг — /products/1, /products/2, /blog/react-intro гэх мэт. Эдгээрийг dynamic route гэдэг. Нэг Route-д бүх тохиолдлыг барьж авдаг энэ механизмыг сурцгаая!
Dynamic route үүсгэх
URL-д : тэмдэгтэй хэсэг нь parameter буюу өөрчлөгдөх хувьсагч:
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/courses" element={<CourseList />} />
{/* :courseId нь dynamic хэсэг — ямар ч утга байж болно */}
<Route path="/courses/:courseId" element={<CourseDetail />} />
{/* Хоёр parameter зэрэг байж болно */}
<Route
path="/courses/:courseId/lessons/:lessonId"
element={<Lesson />}
/>
</Routes>
</BrowserRouter>
);
}
/courses/javascript, /courses/react, /courses/python — бүгд нэг Route-д тохирно, зөвхөн courseId-н утга өөрчлөгдөнө.
useParams hook
URL-с parameter-уудыг уншихад useParams ашиглана:
import { useParams, Link } from "react-router-dom";
const courses = [
{ id: "javascript", title: "JavaScript үндэс", lessons: 30 },
{ id: "react", title: "React үндэс", lessons: 45 },
{ id: "python", title: "Python үндэс", lessons: 28 },
];
// /courses хуудас — жагсаалт
function CourseList() {
return (
<div>
<h1>Сургалтууд</h1>
{courses.map((course) => (
<div key={course.id}>
{/* Link-н to нь dynamic ID ашиглана */}
<Link to={`/courses/${course.id}`}>
<h2>{course.title}</h2>
<p>{course.lessons} хичээл</p>
</Link>
</div>
))}
</div>
);
}
// /courses/:courseId хуудас — тодорхой курс
function CourseDetail() {
// URL-с courseId-г уншина
const { courseId } = useParams();
const course = courses.find((c) => c.id === courseId);
if (!course) {
return <p>Курс олдсонгүй.</p>;
}
return (
<div>
<Link to="/courses">← Бүх сургалтууд</Link>
<h1>{course.title}</h1>
<p>Нийт {course.lessons} хичээл</p>
</div>
);
}
API-с өгөгдөл татах жишээ
Жинхэнэ аппад params ашиглан API дуудна:
import { useParams, Link } from "react-router-dom";
import { useState, useEffect } from "react";
function BlogPost() {
const { slug } = useParams(); // /blog/:slug
const [post, setPost] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// slug өөрчлөгдөх болгонд дахин татна
async function fetchPost() {
setLoading(true);
setError(null);
try {
const res = await fetch(`/api/posts/${slug}`);
if (!res.ok) throw new Error("Нийтлэл олдсонгүй");
const data = await res.json();
setPost(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
fetchPost();
}, [slug]); // slug dependency-д байх ёстой!
if (loading) return <p>Ачааллаж байна...</p>;
if (error) return <p style={{ color: "red" }}>{error}</p>;
return (
<article>
<h1>{post.title}</h1>
<p style={{ color: "#6b7280" }}>{post.publishedAt}</p>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}
useSearchParams hook
URL-н query string (?) параметрийг унших, өөрчлөх:
import { useSearchParams, Link } from "react-router-dom";
const allProducts = [
{ id: 1, name: "Гар утас", category: "tech", price: 800000 },
{ id: 2, name: "Цамц", category: "clothes", price: 45000 },
{ id: 3, name: "Зөөврийн компьютер", category: "tech", price: 2500000 },
{ id: 4, name: "Өмд", category: "clothes", price: 60000 },
];
function ProductList() {
// URL: /products?category=tech&sort=price
const [searchParams, setSearchParams] = useSearchParams();
const category = searchParams.get("category") ?? "all";
const sort = searchParams.get("sort") ?? "name";
const filtered = allProducts
.filter((p) => category === "all" || p.category === category)
.sort((a, b) =>
sort === "price" ? a.price - b.price : a.name.localeCompare(b.name),
);
function handleCategory(cat) {
// URL-г шинэчлэнэ, хуудас reload хийхгүй
setSearchParams({ category: cat, sort });
}
return (
<div>
<div style={{ display: "flex", gap: "8px", marginBottom: "16px" }}>
<button onClick={() => handleCategory("all")}>Бүгд</button>
<button onClick={() => handleCategory("tech")}>Технологи</button>
<button onClick={() => handleCategory("clothes")}>Хувцас</button>
</div>
<ul>
{filtered.map((p) => (
<li key={p.id}>
<Link to={`/products/${p.id}`}>
{p.name} — {p.price.toLocaleString()}₮
</Link>
</li>
))}
</ul>
</div>
);
}
useSearchParams ашигласнаар URL нь аппын байдлыг тусгадаг — хэрэглэгч хуудсыг bookmark хийж, буцаж ирэхэд яг нэгэн байдалтай харагдана.
Дараагийн хичээлд:
Nested маршрут сурна — route дотор route үүсгэн нарийн төвөгтэй хуудасны бүтэц хэрхэн зохион байгуулахыг ойлгоно. Dashboard, settings зэрэг дэд хэсэгтэй хуудасд энэ pattern маш хэрэгтэй.