Динамические маршруты
Динамические маршруты — URL-паттерны с параметрами (:id, :slug), позволяющие одному определению маршрута обрабатывать множество конкретных адресов.
Зачем нужно
Без динамических маршрутов пришлось бы регистрировать отдельный маршрут для каждого пользователя, товара или статьи: /users/1, /users/2, ... Параметры маршрута (route params) — механизм создания шаблонного URL, где часть пути становится переменной. Это фундамент для страниц товаров, профилей, статей и любого контента с уникальным идентификатором.
Где используется
- Профили пользователей:
/users/:userId - Карточки товаров:
/products/:productId - Статьи блога:
/blog/:year/:month/:slug - Вложенные ресурсы:
/projects/:projectId/tasks/:taskId - Catch-all маршруты:
/docs/*
React Router v6
import { Routes, Route, useParams, useSearchParams, Link } from 'react-router-dom';
function App() {
return (
<Routes>
{/* :userId — динамический сегмент */}
<Route path="/users/:userId" element={<UserProfile />} />
{/* Несколько параметров */}
<Route path="/blog/:year/:slug" element={<BlogPost />} />
{/* Необязательный параметр через ? */}
<Route path="/products/:id/:tab?" element={<ProductPage />} />
{/* Catch-all — матчит /docs и всё под ним */}
<Route path="/docs/*" element={<DocsPage />} />
</Routes>
);
}
// Получение параметров через useParams
function UserProfile() {
const { userId } = useParams; // userId — строка
const [user, setUser] = React.useState(null);
React.useEffect(() => {
// При изменении userId перезапрашиваем данные
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(setUser);
}, [userId]); // зависимость от userId!
if (!user) return <p>Загрузка...</p>;
return <div><h1>{user.name}</h1><p>{user.email}</p></div>;
}
Query-параметры (search params)
// URL: /products?category=electronics&sort=price&page=2
function ProductList() {
const [searchParams, setSearchParams] = useSearchParams;
// Чтение query-параметров
const category = searchParams.get('category') || 'all';
const sort = searchParams.get('sort') || 'default';
const page = Number(searchParams.get('page')) || 1;
// Обновление query-параметров без перезагрузки
const handleCategoryChange = (newCategory) => {
setSearchParams(prev => {
prev.set('category', newCategory);
prev.set('page', '1'); // сброс страницы при смене категории
return prev;
});
};
return (
<div>
<select value={category} onChange={e => handleCategoryChange(e.target.value)}>
<option value="all">Все</option>
<option value="electronics">Электроника</option>
<option value="clothing">Одежда</option>
</select>
{/* ...список товаров */}
</div>
);
}
Next.js: динамические маршруты
app/
users/
[userId]/
page.tsx ← /users/:userId
blog/
[year]/
[slug]/
page.tsx ← /blog/:year/:slug
docs/
[...path]/
page.tsx ← /docs/:path* (catch-all)
// app/users/[userId]/page.tsx
interface Props {
params: { userId: string };
}
export default async function UserPage({ params }: Props) {
const user = await fetchUser(params.userId);
return <div><h1>{user.name}</h1></div>;
}
Частые ошибки
- Не добавляют
userIdв deps массивuseEffect— при навигации между профилями (/users/1→/users/2) компонент не перезапрашивает данные. - Парсят params как числа без проверки —
params.idвсегда строка;Number(params.id)может вернутьNaNдля невалидного URL. - Путают route params и query params —
/products/:id— route param (обязательная часть пути);/products?id=42— query param (необязательный).
Связанные темы
- _MOC SPA
- Клиентский роутинг -- как работает
- Вложенные маршруты
- History API и hash-routing
- SSG -- Static Site Generation