Макеты и вложенные маршруты
У страниц блога общая шапка и подвал. Чтобы не повторять их в каждом файле, используют макет (layout) — маршрут, который рисует общую часть и оставляет место для вложенной страницы. Это место обозначают компонентом Outlet.
Компонент макета
Создайте файл app/routes/layout.tsx:
// app/routes/layout.tsx
import { Outlet } from "react-router";
export default function Layout() {
return (
<>
<header>Мой блог</header>
<main>
<Outlet />
</main>
<footer>© 2026</footer>
</>
);
}На месте Outlet будет отрисована та вложенная страница, адрес которой открыт сейчас.
Подключение макета
Функция layout(файл, [маршруты]) оборачивает маршруты в макет:
// app/routes.ts
import { type RouteConfig, index, layout, route } from "@react-router/dev/routes";
export default [
layout("routes/layout.tsx", [
index("routes/home.tsx"),
route("about", "routes/about.tsx"),
]),
] satisfies RouteConfig;Теперь и /, и /about показываются с шапкой «Мой блог» и подвалом. Сам layout не добавляет ничего к адресу.
Вложенный маршрут с адресом
Если третьим аргументом передать route массив, маршрут станет родителем: его адрес — начало адресов детей, а компонент — макет для них. Индексный маршрут внутри — страница для адреса самого родителя:
// app/routes.ts
route("dashboard", "routes/dashboard.tsx", [
index("routes/dashboard-home.tsx"), // /dashboard
route("stats", "routes/dashboard-stats.tsx"), // /dashboard/stats
]),В app/routes/dashboard.tsx тоже должен быть Outlet, иначе дочерние страницы не появятся.
Только префикс
Когда нужен общий адрес без общего компонента, используют prefix:
// app/routes.ts
import { prefix, route } from "@react-router/dev/routes";
// внутри массива маршрутов:
...prefix("admin", [
route("posts", "routes/admin-posts.tsx"), // /admin/posts
route("users", "routes/admin-users.tsx"), // /admin/users
]),prefix возвращает массив, поэтому его разворачивают оператором ....
Сводка
| Функция | Адрес | Компонент |
|---|---|---|
route с детьми | Добавляет часть адреса | Макет с Outlet |
layout | Не меняет | Макет с Outlet |
prefix | Добавляет часть адреса | Нет |
index | Адрес родителя | Страница |
Частая ошибка
Маршруты добавлены внутрь layout, но на странице видна только шапка. Причина почти всегда одна — в компоненте макета забыли <Outlet />. Макет сам решает, где показать дочернюю страницу, и без Outlet она просто не выводится.