Встановлення та базова конфігурація React Router v7
Встановлення та базова конфігурація React Router v7
🔗 Офіційний референс: React Router v7 Installation (Library Mode)
🎯 Мета лекції
- Встановити React Router v7 як бібліотеку для існуючого React-проєкту.
- Зрозуміти різницю між режимом бібліотеки та фреймворку React Router.
- Налаштувати базову маршрутизацію через компоненти
<BrowserRouter>,<Routes>та<Route>. - Створити перший SPA-застосунок із кількома сторінками без перезавантаження.
🔑 Ключові терміни
- React Router (Library Mode): бібліотека клієнтської маршрутизації для React без серверних можливостей.
- BrowserRouter: компонент, що використовує History API браузера для синхронізації UI з URL.
- Routes: контейнер, що визначає набір можливих маршрутів застосунку.
- Route: декларативне відображення URL-шляху на React-компонент.
React Router як бібліотека vs фреймворк
React Router v7 підтримує два режими роботи:
Режим фреймворку (Framework Mode)
Повноцінний full-stack фреймворк із:
- Серверним рендерингом (SSR)
- Завантаженням даних на сервері (Server Loaders)
- Серверними діями (Server Actions)
- Автоматичним code-splitting
- Вбудованою збіркою та деплоєм
Цей режим конкурує з Next.js та Remix (насправді, React Router v7 — це еволюція Remix).
Режим бібліотеки (Library Mode) — наш фокус
Класична клієнтська бібліотека маршрутизації для існуючих React-застосунків:
- Працює виключно на клієнті (без SSR)
- Інтегрується з будь-яким збирачем (Vite, Webpack, Parcel)
- Не нав'язує структуру проєкту
- Сумісна з будь-яким бекендом (REST API, GraphQL, WebSocket)
Встановлення
React Router v7 поставляється як єдиний пакет react-router (раніше це був react-router-dom для веб-застосунків). Для веб-проєктів зараз рекомендується встановлювати саме react-router, який автоматично включає всі необхідні веб-API.
npm install react-router
pnpm add react-router
yarn add react-router
react-router-dom все ще працює і є псевдонімом для react-router. Проте для нових проєктів рекомендується використовувати просто react-router.Інтеграція з Vite-проєктом
Припустимо, у нас є стандартний Vite + React + TypeScript проєкт:
npm create vite@latest my-spa -- --template react-ts
cd my-spa
npm install
npm install react-router
Структура проєкту:
Перший крок: обгортання у BrowserRouter
BrowserRouter — це кореневий компонент React Router, що використовує History API браузера (методи pushState, replaceState, подія popstate) для синхронізації UI з URL без перезавантаження сторінки.
// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router";
import App from "./App";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
main.tsx, а не у App.tsx?BrowserRouter створює контекст маршрутизації, доступний для всіх дочірніх компонентів через React Context. Розміщення на найвищому рівні гарантує, що весь застосунок має доступ до хуків маршрутизації (useNavigate, useParams, useLocation тощо).<App> у <BrowserRouter> всередині самого компонента App. Це призведе до того, що хуки маршрутизації не працюватимуть поза компонентом App.✅ Правильно:<BrowserRouter> у main.tsx на найвищому рівні.❌ Неправильно:
<BrowserRouter> всередині App.tsx.Другий крок: визначення маршрутів
Тепер визначимо базові маршрути через компоненти <Routes> та <Route>.
// src/App.tsx
import { Routes, Route } from "react-router";
function HomePage() {
return (
<div>
<h1>Головна сторінка</h1>
<p>Ласкаво просимо до нашого застосунку!</p>
</div>
);
}
function AboutPage() {
return (
<div>
<h1>Про нас</h1>
<p>Ми команда розробників, що створюють чудові SPA.</p>
</div>
);
}
function ContactPage() {
return (
<div>
<h1>Контакти</h1>
<p>Email: contact@example.com</p>
</div>
);
}
function App() {
return (
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/contact" element={<ContactPage />} />
</Routes>
);
}
export default App;
<Route>:path— URL-шлях, що відповідає цьому маршруту (наприклад,/,/about,/users/:id).element— React-компонент, що рендериться, коли URL збігається зpath.
/about, рендериться <AboutPage />.Третій крок: навігація через Link
Щоб переходити між сторінками без перезавантаження, використовуємо компонент <Link>:
// src/App.tsx
import { Routes, Route, Link } from "react-router";
function Navigation() {
return (
<nav style={{ padding: "1rem", borderBottom: "1px solid #ccc" }}>
<Link to="/" style={{ marginRight: "1rem" }}>
Головна
</Link>
<Link to="/about" style={{ marginRight: "1rem" }}>
Про нас
</Link>
<Link to="/contact">Контакти</Link>
</nav>
);
}
function HomePage() {
return (
<div>
<h1>Головна сторінка</h1>
<p>Ласкаво просимо до нашого застосунку!</p>
</div>
);
}
function AboutPage() {
return (
<div>
<h1>Про нас</h1>
<p>Ми команда розробників, що створюють чудові SPA.</p>
</div>
);
}
function ContactPage() {
return (
<div>
<h1>Контакти</h1>
<p>Email: contact@example.com</p>
</div>
);
}
function App() {
return (
<>
<Navigation />
<main style={{ padding: "1rem" }}>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/contact" element={<ContactPage />} />
</Routes>
</main>
</>
);
}
export default App;
<Link> та <a>:<a href="/about">— викликає повне перезавантаження сторінки, втрачається весь стан React, відбувається новий запит до сервера.<Link to="/about">— клієнтська навігація: React Router перехоплює клік, змінює URL через History API, React перерендерює компонент без перезавантаження сторінки.
<Link> для внутрішньої навігації у SPA.Запуск та тестування
npm run dev
Відкрийте браузер за адресою http://localhost:5173. Натискайте на посилання навігації — сторінка не перезавантажується, URL змінюється миттєво, контент оновлюється плавно.
<Link> ви не побачите нових запитів до сервера за HTML-документами — вся навігація відбувається на клієнті через JavaScript.Альтернативний синтаксис: Data Router API через createBrowserRouter
React Router v7 пропонує два способи визначення маршрутів:
- JSX-синтаксис (який ми щойно розглянули) — через компоненти
<Routes>та<Route> - Об'єктний синтаксис — через функцію
createBrowserRouterта масив об'єктів маршрутів
Другий підхід називається Data Router API і надає додаткові можливості:
Переваги Data Router API
- Data Loaders — завантаження даних до рендерингу компонента
- Actions — обробка форм на рівні маршруту
- Error Boundaries — обробка помилок на рівні маршруту
- Lazy Loading — динамічне завантаження компонентів
- Централізована конфігурація — всі маршрути в одному місці
Базовий приклад з createBrowserRouter
// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { createBrowserRouter, RouterProvider } from "react-router";
import "./index.css";
// Компоненти сторінок
function HomePage() {
return (
<div>
<h1>Головна сторінка</h1>
<p>Ласкаво просимо до нашого застосунку!</p>
</div>
);
}
function AboutPage() {
return (
<div>
<h1>Про нас</h1>
<p>Ми команда розробників, що створюють чудові SPA.</p>
</div>
);
}
function ContactPage() {
return (
<div>
<h1>Контакти</h1>
<p>Email: contact@example.com</p>
</div>
);
}
// Визначення маршрутів через масив об'єктів
const router = createBrowserRouter([
{
path: "/",
element: <HomePage />,
},
{
path: "/about",
element: <AboutPage />,
},
{
path: "/contact",
element: <ContactPage />,
},
]);
// Рендеринг застосунку
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
JSX-синтаксис (<Routes>) | Data Router API (createBrowserRouter) |
|---|---|
<BrowserRouter> + <Routes> | createBrowserRouter() + <RouterProvider> |
| Маршрути визначаються в JSX | Маршрути визначаються в масиві об'єктів |
| Навігація та базовий роутинг | Додатково: loaders, actions, errorElement |
| Маршрути можуть бути розподілені по файлах | Централізована конфігурація |
- Для простих SPA без завантаження даних — обидва підходи рівноцінні.
- Для складних застосунків із data fetching, формами, обробкою помилок — Data Router API краще.
Додавання Layout та навігації
// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { createBrowserRouter, RouterProvider, Link, Outlet } from "react-router";
import "./index.css";
// Layout компонент із навігацією
function RootLayout() {
return (
<>
<nav style={{ padding: "1rem", borderBottom: "1px solid #ccc" }}>
<Link to="/" style={{ marginRight: "1rem" }}>
Головна
</Link>
<Link to="/about" style={{ marginRight: "1rem" }}>
Про нас
</Link>
<Link to="/contact">Контакти</Link>
</nav>
<main style={{ padding: "1rem" }}>
{/* Тут рендериться активний маршрут */}
<Outlet />
</main>
</>
);
}
function HomePage() {
return (
<div>
<h1>Головна сторінка</h1>
<p>Ласкаво просимо до нашого застосунку!</p>
</div>
);
}
function AboutPage() {
return (
<div>
<h1>Про нас</h1>
<p>Ми команда розробників, що створюють чудові SPA.</p>
</div>
);
}
function ContactPage() {
return (
<div>
<h1>Контакти</h1>
<p>Email: contact@example.com</p>
</div>
);
}
// Маршрути з Layout
const router = createBrowserRouter([
{
path: "/",
element: <RootLayout />,
children: [
{
index: true, // Еквівалент path: ""
element: <HomePage />,
},
{
path: "about",
element: <AboutPage />,
},
{
path: "contact",
element: <ContactPage />,
},
],
},
]);
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
index: true еквівалентна <Route index element={...} /> у JSX-синтаксисі. Це маршрут за замовчуванням, що рендериться за базового URL батьківського маршруту.Винесення конфігурації у окремий файл
Для великих застосунків рекомендується винести конфігурацію маршрутів у окремий файл:
// src/router.tsx
import { createBrowserRouter } from "react-router";
import RootLayout from "./layouts/RootLayout";
import HomePage from "./pages/HomePage";
import AboutPage from "./pages/AboutPage";
import ContactPage from "./pages/ContactPage";
export const router = createBrowserRouter([
{
path: "/",
element: <RootLayout />,
children: [
{
index: true,
element: <HomePage />,
},
{
path: "about",
element: <AboutPage />,
},
{
path: "contact",
element: <ContactPage />,
},
],
},
]);
// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider } from "react-router";
import { router } from "./router";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
createBrowserRouter.Це допоможе вам:- Зрозуміти концепції незалежно від синтаксису
- Вміти читати код в обох стилях
- Обрати підхід, що краще підходить для вашого проєкту
Альтернатива BrowserRouter: HashRouter
Якщо ваш проєкт розгортається на статичному хостингу (GitHub Pages, Netlify) без налаштування серверних редиректів, можна використовувати HashRouter.
JSX-синтаксис
import { HashRouter } from "react-router";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<HashRouter>
<App />
</HashRouter>
</React.StrictMode>
);
Data Router API
import { createHashRouter, RouterProvider } from "react-router";
const router = createHashRouter([
{
path: "/",
element: <HomePage />,
},
{
path: "/about",
element: <AboutPage />,
},
]);
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
HashRouter використовує hash-частину URL (після #):
https://example.com/#/abouthttps://example.com/#/users/123
| BrowserRouter | HashRouter |
|---|---|
/about, /users/123 | /#/about, /#/users/123 |
| Потребує серверної конфігурації для SPA | Працює без серверної конфігурації |
| Чистіші URL, краще для SEO | URL містять #, гірше для SEO |
BrowserRouter завжди, коли це можливо. HashRouter — лише для обмежених середовищ без доступу до серверної конфігурації.Практичне завдання
Розширте базовий застосунок:
- Створіть новий компонент
ServicesPage, що відображає список послуг (наприклад, "Веб-розробка", "Мобільні додатки", "Консалтинг"). - Додайте маршрут
/servicesу<Routes>. - Додайте посилання "Послуги" у компонент
Navigation. - Переконайтеся, що навігація працює без перезавантаження сторінки.
// src/App.tsx
import { Routes, Route, Link } from "react-router";
function Navigation() {
return (
<nav style={{ padding: "1rem", borderBottom: "1px solid #ccc" }}>
<Link to="/" style={{ marginRight: "1rem" }}>
Головна
</Link>
<Link to="/about" style={{ marginRight: "1rem" }}>
Про нас
</Link>
<Link to="/services" style={{ marginRight: "1rem" }}>
Послуги
</Link>
<Link to="/contact">Контакти</Link>
</nav>
);
}
function HomePage() {
return (
<div>
<h1>Головна сторінка</h1>
<p>Ласкаво просимо до нашого застосунку!</p>
</div>
);
}
function AboutPage() {
return (
<div>
<h1>Про нас</h1>
<p>Ми команда розробників, що створюють чудові SPA.</p>
</div>
);
}
function ServicesPage() {
return (
<div>
<h1>Наші послуги</h1>
<ul>
<li>Веб-розробка</li>
<li>Мобільні додатки</li>
<li>Консалтинг</li>
<li>UI/UX дизайн</li>
</ul>
</div>
);
}
function ContactPage() {
return (
<div>
<h1>Контакти</h1>
<p>Email: contact@example.com</p>
</div>
);
}
function App() {
return (
<>
<Navigation />
<main style={{ padding: "1rem" }}>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/services" element={<ServicesPage />} />
<Route path="/contact" element={<ContactPage />} />
</Routes>
</main>
</>
);
}
export default App;
Перевірка:
- Запустіть
npm run dev. - Натисніть на посилання "Послуги" — URL зміниться на
/services, відобразиться список послуг. - Натисніть "Назад" у браузері — ви повернетесь на попередню сторінку.
- Оновіть сторінку на
/services— якщо dev-сервер Vite налаштований правильно, сторінка завантажиться без 404 (Vite автоматично обробляє це у режимі розробки).
Підсумок
✅ Що ми опанували
- Встановили React Router v7 у режимі бібліотеки через
npm install react-router. - Обгорнули застосунок у
<BrowserRouter>для підключення History API. - Визначили маршрути через декларативні компоненти
<Routes>та<Route>. - Реалізували навігацію через компонент
<Link>без перезавантаження сторінки. - Зрозуміли різницю між
BrowserRouter(чисті URL) таHashRouter(hash-based).
🎯 Наступні кроки
У наступних лекціях ми розглянемо:
- Вкладені маршрути та
<Outlet>для складних макетів. - Динамічні сегменти URL (
/users/:id) таuseParams. - Активні посилання через
<NavLink>. - Програмна навігація через
useNavigate. - Обробка 404 та помилок.
React Router v7: Маршрутизація в SPA
Повний курс клієнтської маршрутизації через React Router v7 у режимі бібліотеки: від базової конфігурації до складних вкладених маршрутів, динамічних параметрів, програмної навігації та обробки помилок.
Вкладені маршрути та Outlet: архітектура складних макетів
Організація вкладеної маршрутизації через Route-дерево, використання Outlet для рендерингу дочірніх компонентів, Layout Routes для спільних обгорток, Index Routes як сторінки за замовчуванням.