Nested маршрут
Өмнөх хичээлд React Router-н үндсийг сурсан. Олон аппад нэг хуудасны дотор дахин хэд хэдэн дэд хуудас байдаг — жишээ нь /settings/profile, /settings/password, /settings/notifications. Энийг nested route буюу шатлалт маршрут гэдэг. Аппын бүтцийг ойлгомжтой зохион байгуулах маш хэрэгтэй pattern!
Nested route гэж яах вэ?
Route дотор Route үүсгэснээр шатлалт бүтэц хийнэ. Parent route-н element-д <Outlet /> байх ёстой — тэр газарт child route рендерлэгдэнэ:
import { BrowserRouter, Routes, Route, Link, Outlet } from "react-router-dom";
// Settings хуудасны layout — дэд цэстэй
function SettingsLayout() {
return (
<div style={{ display: "flex", gap: "24px" }}>
{/* Зүүн талын дэд цэс */}
<aside style={{ width: "200px" }}>
<nav style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
<Link to="/settings/profile">Профайл</Link>
<Link to="/settings/password">Нууц үг</Link>
<Link to="/settings/notifications">Мэдэгдэл</Link>
</nav>
</aside>
{/* Баруун талд child route рендерлэгдэнэ */}
<main style={{ flex: 1 }}>
<Outlet />
</main>
</div>
);
}
function ProfileSettings() {
return <h2>Профайл тохиргоо</h2>;
}
function PasswordSettings() {
return <h2>Нууц үг солих</h2>;
}
function NotificationSettings() {
return <h2>Мэдэгдлийн тохиргоо</h2>;
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/settings" element={<SettingsLayout />}>
{/* index — "/settings" хаягт харагдах default child */}
<Route index element={<ProfileSettings />} />
<Route path="profile" element={<ProfileSettings />} />
<Route path="password" element={<PasswordSettings />} />
<Route path="notifications" element={<NotificationSettings />} />
</Route>
</Routes>
</BrowserRouter>
);
}
/settings руу орвол SettingsLayout + ProfileSettings хамт харагдана. /settings/password руу орвол SettingsLayout хэвээр байж, зөвхөн <Outlet /> байрлал PasswordSettings-ээр солигдоно.
Бодит жишээ: Dashboard
Удирдлагын панел нь nested route-н хамгийн нийтлэг хэрэглээ:
import { Routes, Route, NavLink, Outlet, useNavigate } from "react-router-dom";
function DashboardLayout() {
const navigate = useNavigate();
const navStyle = ({ isActive }) => ({
display: "block",
padding: "10px 16px",
borderRadius: "6px",
background: isActive ? "#1e293b" : "transparent",
color: isActive ? "#4ade80" : "#94a3b8",
textDecoration: "none",
});
return (
<div style={{ display: "flex", minHeight: "100vh" }}>
{/* Sidebar */}
<aside style={{ width: "240px", background: "#0f172a", padding: "16px" }}>
<h2 style={{ color: "#f1f5f9", marginBottom: "24px" }}>Удирдлага</h2>
<nav style={{ display: "flex", flexDirection: "column", gap: "4px" }}>
<NavLink to="/dashboard" end style={navStyle}>
Нүүр
</NavLink>
<NavLink to="/dashboard/users" style={navStyle}>
Хэрэглэгчид
</NavLink>
<NavLink to="/dashboard/orders" style={navStyle}>
Захиалгууд
</NavLink>
<NavLink to="/dashboard/analytics" style={navStyle}>
Статистик
</NavLink>
</nav>
</aside>
{/* Main content */}
<main style={{ flex: 1, padding: "24px", background: "#0b1120" }}>
<Outlet />
</main>
</div>
);
}
function DashboardHome() {
return <h1 style={{ color: "#f1f5f9" }}>Тавтай морил!</h1>;
}
function Users() {
return <h1 style={{ color: "#f1f5f9" }}>Хэрэглэгчдийн жагсаалт</h1>;
}
function Orders() {
return <h1 style={{ color: "#f1f5f9" }}>Захиалгуудын жагсаалт</h1>;
}
function Analytics() {
return <h1 style={{ color: "#f1f5f9" }}>Статистик мэдээлэл</h1>;
}
Гүн шатлал — route дотор route дотор route
Nested route-ийг дурын гүнд үүсгэж болно:
function App() {
return (
<BrowserRouter>
<Routes>
{/* 1-р түвшин: нийтлэг layout */}
<Route path="/" element={<AppLayout />}>
{/* 2-р түвшин: dashboard layout */}
<Route path="dashboard" element={<DashboardLayout />}>
<Route index element={<DashboardHome />} />
<Route path="users" element={<Users />} />
{/* 3-р түвшин: хэрэглэгчийн дэлгэрэнгүй */}
<Route path="users/:userId" element={<UserDetail />} />
<Route path="orders" element={<Orders />} />
<Route path="analytics" element={<Analytics />} />
</Route>
{/* 2-р түвшин: settings layout */}
<Route path="settings" element={<SettingsLayout />}>
<Route index element={<ProfileSettings />} />
<Route path="password" element={<PasswordSettings />} />
</Route>
</Route>
</Routes>
</BrowserRouter>
);
}
URL /dashboard/users/42 гэвэл:
AppLayoutрендерлэгдэнэ- Түүний
<Outlet />-дDashboardLayoutрендерлэгдэнэ - Түүний
<Outlet />-дUserDetail(userId = "42") рендерлэгдэнэ
NavLink-н end prop
NavLink-д end prop байхгүй бол parent path нь child route-д ч "active" байгаа мэт харагддаг:
// ❌ "/dashboard/users" руу орсон үед "/dashboard" ч active харагдана
<NavLink to="/dashboard" style={navStyle}>Нүүр</NavLink>
// ✅ Яг "/dashboard" path байхад л active харагдана
<NavLink to="/dashboard" end style={navStyle}>Нүүр</NavLink>
end prop нь to-н утга URL-н төгсгөлтэй яг тохирох үед л active болно гэсэн үг.
Дараагийн хичээлд:
Өгөгдөл татах сурна — fetch API ба useEffect хослуулан серверээс өгөгдөл хэрхэн татах, loading болон error төлвийг хэрхэн зохицуулахыг эзэмшинэ.