Legacy Routing: Компонентний підхід
Legacy Routing: Компонентний підхід
BrowserRouter, але не дозволяє використовувати нові Data APIs (loaders, actions). Використовуйте цей підхід тільки для підтримки старих проектів.До появи Data Router (v6.4+), React Router був суто компонентною бібліотекою. Ми визначали маршрути прямо в JSX, як звичайні компоненти.
1. Налаштування (Old School)
Замість createBrowserRouter та RouterProvider, ми використовували компонент-обгортку <BrowserRouter>.
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
{/* Обгортаємо весь додаток */}
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
2. Визначення маршрутів
Маршрути визначаються за допомогою компонентів <Routes> (раніше <Switch> у v5) та <Route>.
import { Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import NotFound from './pages/NotFound';
function App() {
return (
<div className="app">
<header>Моє Меню</header>
<main>
{/* Тут React Router вирішує, що показати */}
<Routes>
{/* path - URL, element - Компонент */}
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
{/* Wildcard маршрут для 404 */}
<Route path="*" element={<NotFound />} />
</Routes>
</main>
</div>
);
}
3. Вкладеність (Legacy Style)
У старому підході вкладені маршрути можна було робити двома способами.
Спосіб А: Вкладені <Route> (як у v6+)
Це схоже на сучасний підхід, але без конфігураційного об'єкта.
<Route path="/dashboard" element={<DashboardLayout />}>
<Route index element={<DashboardHome />} />
<Route path="settings" element={<Settings />} />
</Route>
У цьому випадку DashboardLayout повинен мати <Outlet />.
Спосіб Б: Розподілені <Routes> (v5 style)
Часто маршрути визначали глибоко всередині компонентів.
<Route path="/dashboard/*" element={<Dashboard />} />
function Dashboard() {
return (
<div>
<h1>Дашборд</h1>
{/* Визначаємо під-маршрути прямо тут */}
<Routes>
<Route path="/" element={<Stats />} />
<Route path="settings" element={<Settings />} />
</Routes>
</div>
);
}
Цей підхід робив код важчим для розуміння, оскільки карта маршрутів була "розмазана" по всьому додатку.
4. Завантаження даних (useEffect)
Оскільки у нас немає loader, ми змушені використовувати useEffect для отримання даних. Це призводить до проблеми "водоспадів", описаної в основному курсі.
function ProductPage() {
const { id } = useParams();
const [data, setData] = useState(null);
useEffect(() => {
// Починаємо завантаження тільки після рендеру
fetchProduct(id).then(setData);
}, [id]);
if (!data) return <Spinner />;
return <div>{data.name}</div>;
}
Чому ми від цього відмовляємось?
- Водоспади даних: Компонент-дитина не починає вантажитися, поки батько не відрендериться.
- Зв'язаність: Логіка роутінгу змішана з логікою відображення (JSX).
- Продуктивність: Браузер завантажує код JS, потім виконує React, потім розуміє, які дані потрібні. Data Router (v6.4+/v7) робить це паралельно.
Якщо ви починаєте новий проект, використовуйте тільки createBrowserRouter або routes.ts (v7).
Просунуті Патерни
Ми вже вміємо будувати повноцінні додатки. Але що робити зі складними сценаріями? Авторизація, оптимізація повільних запитів, інтерактивність без переходу на нову сторінку.
Redux: Еволюція управління станом
Повний посібник з Redux: від фундаментальних принципів та "класичного" підходу до сучасного Redux Toolkit та RTK Query.