React Router: Навігаційна система сучасного вебу

Legacy Routing: Компонентний підхід

Legacy Routing: Компонентний підхід

Цей розділ описує старий підхід до роутінгу (v4/v5/v6-legacy). Він все ще підтримується в v7 через BrowserRouter, але не дозволяє використовувати нові Data APIs (loaders, actions). Використовуйте цей підхід тільки для підтримки старих проектів.

До появи Data Router (v6.4+), React Router був суто компонентною бібліотекою. Ми визначали маршрути прямо в JSX, як звичайні компоненти.

1. Налаштування (Old School)

Замість createBrowserRouter та RouterProvider, ми використовували компонент-обгортку <BrowserRouter>.

src/main.jsx
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>.

src/App.jsx
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)

Часто маршрути визначали глибоко всередині компонентів.

src/App.jsx
<Route path="/dashboard/*" element={<Dashboard />} />
src/pages/Dashboard.jsx
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>;
}

Чому ми від цього відмовляємось?

  1. Водоспади даних: Компонент-дитина не починає вантажитися, поки батько не відрендериться.
  2. Зв'язаність: Логіка роутінгу змішана з логікою відображення (JSX).
  3. Продуктивність: Браузер завантажує код JS, потім виконує React, потім розуміє, які дані потрібні. Data Router (v6.4+/v7) робить це паралельно.

Якщо ви починаєте новий проект, використовуйте тільки createBrowserRouter або routes.ts (v7).

Copyright © 2026