Це "кілер-фіча" React Router. Якщо ви зрозумієте цей розділ, ви зрозумієте 80% архітектури складних React-додатків.
У більшості роутерів (в інших мовах чи фреймворках) маршрут — це просто спосіб зіставити URL з екраном. В React Router маршрут — це спосіб зіставити сегмент URL з сегментом UI.
Подивіться на типовий веб-інтерфейс, наприклад, панель керування:
/dashboard/settings/profile
+----------------------------------------------------+
| Global Navbar (Лого, Меню) |
| +------------------------------------------------+ |
| | Dashboard Sidebar (Меню дашборда) | |
| | +--------------------------------------------+ | |
| | | Settings Tabs (Профіль, Безпека) | | |
| | | +----------------------------------------+ | | |
| | | | | | | |
| | | | Profile Form (Власне контент) | | | |
| | | | | | | |
| | | +----------------------------------------+ | | |
| | +--------------------------------------------+ | |
| +------------------------------------------------+ |
+----------------------------------------------------+
/ відповідає за Global Navbar/dashboard додає Sidebar/settings додає Tabs/profile показує FormКоли URL змінюється з /dashboard/settings/profile на /dashboard/settings/security:
React Router дозволяє відобразити цю вкладеність прямо в конфігурації маршрутів.
<Outlet>Щоб реалізувати цю вкладеність, батьківський маршрут повинен знати, куди саме вставити дочірній компонент. Для цього використовується компонент <Outlet>.
Думайте про <Outlet> як про props.children, але контрольований роутером.
У попередніх уроках ми мали проблему: навігаційне меню довелося б копіювати на кожну сторінку. Давайте виправимо це, створивши спільний макет для всього сайту.
import { Outlet, NavLink } from 'react-router-dom'
export default function RootLayout() {
return (
<div className="app-container">
{/* Ця частина буде на ВСІХ сторінках */}
<header>
<nav>
<NavLink to="/">Головна</NavLink>
<NavLink to="/about">Про нас</NavLink>
</nav>
</header>
{/* Сюди роутер підставить контент поточної сторінки */}
<main>
<Outlet />
</main>
<footer>
<p>© 2026 Мій Сайт</p>
</footer>
</div>
)
}
Тепер ми використаємо властивість children в об'єкті маршруту.
import RootLayout from './layouts/RootLayout'
// ... інші імпорти
const router = createBrowserRouter([
{
path: '/',
element: <RootLayout />, // Головний батько
errorElement: <ErrorPage />,
children: [
{
// Це Index Route (про нього нижче)
index: true,
element: <HomePage />,
},
{
path: 'about', // Зверніть увагу: без слеша "/" на початку!
element: <AboutPage />,
},
],
},
])
Що змінилося:
/, рендериться <RootLayout>. Всередині його <Outlet /> рендериться <HomePage>./about, рендериться <RootLayout>. Всередині його <Outlet /> рендериться <AboutPage>.Ви могли помітити index: true замість path: "" або path: "/".
Індексний маршрут — це "маршрут за замовчуванням" для батьківського шляху.
Коли URL точно збігається з шляхом батька (у нашому випадку /), батько показує element, але в <Outlet> було б порожньо, якби не індексний маршрут.
Уявіть це як index.html у папці.
children: [
{
index: true, // URL: /
element: <Home />,
},
{
path: 'products', // URL: /products
element: <ProductsLayout />,
children: [
{ index: true, element: <AllProductsList /> }, // URL: /products
{ path: 'new', element: <NewProductForm /> }, // URL: /products/new
],
},
]
Зверніть увагу, що у дочірніх маршрутах ми пишемо path: "about", а не path: "/about".
/about): Завжди рахується від кореня домену.about): Рахується від шляху батька.Якщо батько має шлях /dashboard, а дитина settings, то кінцевий URL буде /dashboard/settings. Це дозволяє легко змінювати URL батька, не ламаючи всі дочірні маршрути.
Давайте реалізуємо структуру з початку уроку.
const router = createBrowserRouter([
{
path: '/',
element: <RootLayout />, // Має <Outlet>
children: [
{
path: 'dashboard',
element: <DashboardLayout />, // Має свій <Outlet>!
children: [
{
index: true,
element: <DashboardHome />, // Статистика
},
{
path: 'settings',
element: <SettingsLayout />, // І тут теж <Outlet>!
children: [
{ index: true, element: <ProfileSettings /> },
{ path: 'security', element: <SecuritySettings /> },
],
},
],
},
],
},
])
Як це рендериться при URL /dashboard/settings/security:
<RootLayout>
<DashboardLayout>
<SettingsLayout>
<SecuritySettings />
</SettingsLayout>
</DashboardLayout>
</RootLayout>
Кожен макет відповідає тільки за свою частину UI і делегує решту через <Outlet />. Це робить код неймовірно модульним.
<Outlet> — це місце, куди батьківський маршрут виводить дочірній.<Outlet>, коли URL точно збігається з батьківським.Ми побудували статичну структуру. Але що робити, якщо частина URL — це динамічний ID (наприклад, /product/123)? Про це — у наступному розділі.
Динамічна Навігація
Тепер, коли у нас є налаштований роутер, нам потрібно якось переміщатися між сторінками. У світі HTML ми звикли використовувати тег <a>. Але в SPA це "заборонений прийом".
Динамічні Маршрути та Параметри
До цього моменту ми працювали з фіксованими URL: /about, /contact. Але реальні додатки працюють з динамічними даними: користувачі (/user/123), товари (/products/iphone-15) або замовлення (/order/abc-999).