Относительные пути во вложенных маршрутах

В React Router концепция вложенных маршрутов позволяет строить сложные интерфейсы с иерархической структурой URL. Каждый вложенный маршрут может наследовать часть пути от родительского, что делает использование относительных путей ключевым для упрощения конфигурации маршрутов и улучшения читаемости кода.

Вложенные маршруты создаются с помощью компонента <Route> внутри другого <Route>, а отображение дочерних компонентов обеспечивается <Outlet>.

import { BrowserRouter as Router, Routes, Route, Outlet, Link } from 'react-router-dom';

function Dashboard() {
  return (
    <div>
      <h2>Dashboard</h2>
      <nav>
        <Link to="stats">Статистика</Link>
        <Link to="settings">Настройки</Link>
      </nav>
      <Outlet />
    </div>
  );
}

function Stats() {
  return <h3>Статистика</h3>;
}

function Settings() {
  return <h3>Настройки</h3>;
}

function App() {
  return (
    <Router>
      <Routes>
        <Route path="dashboard" element={<Dashboard />}>
          <Route path="stats" element={<Stats />} />
          <Route path="settings" element={<Settings />} />
        </Route>
      </Routes>
    </Router>
  );
}

Относительные пути

Относительный путь — это путь, который интерпретируется относительно текущего URL родителя, а не от корня сайта. В примере выше ссылки "stats" и "settings" внутри <Dashboard> автоматически интерпретируются как /dashboard/stats и /dashboard/settings.

Использование относительных путей позволяет:

  • Избегать дублирования части пути при больших вложенных структурах.
  • Облегчить реорганизацию маршрутов без необходимости менять все ссылки.
  • Сделать код более читаемым и поддерживаемым.

Компоненты <Link> и <NavLink> автоматически понимают относительный путь, если он не начинается с /.

<Link to="profile">Профиль</Link> // Относительно текущего маршрута
<Link to="/profile">Профиль</Link> // Абсолютный путь от корня

Важно учитывать:

  • Относительные пути могут содержать сегменты "../" для перехода на уровень выше.
  • Компонент <NavLink> работает аналогично, поддерживая относительные пути и активные состояния для текущего маршрута.
<Link to="../dashboard">Вернуться к Dashboard</Link>

Относительные пути в useNavigate и useLocation

useNavigate также поддерживает относительные пути, особенно удобно для программной навигации внутри вложенных маршрутов.

import { useNavigate } from 'react-router-dom';

function SettingsButton() {
  const navigate = useNavigate();

  const goToStats = () => {
    navigate('stats'); // Переходит к 'dashboard/stats', если вызвано внутри Dashboard
  };

  return <button onCl ick={goToStats}>Перейти к статистике</button>;
}

Ключевой момент: чтобы путь был интерпретирован как относительный, он не должен начинаться с /. В противном случае React Router будет считать его абсолютным.

Вложенные маршруты с параметрами

Относительные пути также применяются к маршрутам с параметрами.

<Route path="users" element={<Users />}>
  <Route path=":id" element={<UserProfile />} />
</Route>

Внутри <Users>:

<Link to="1">Пользователь 1</Link> // Сформирует /users/1
<Link to="2">Пользователь 2</Link> // Сформирует /users/2

Для возврата на уровень выше используется "../":

<Link to="../">Все пользователи</Link> // Вернёт на /users

Совместное использование <Outlet> и относительных путей

Компонент <Outlet> служит контейнером для дочерних маршрутов, позволяя родителю определять общую структуру интерфейса, а дочерним компонентам рендериться внутри него.

function Users() {
  return (
    <div>
      <h2>Пользователи</h2>
      <nav>
        <Link to="1">Пользователь 1</Link>
        <Link to="2">Пользователь 2</Link>
      </nav>
      <Outlet />
    </div>
  );
}

С использованием <Outlet> и относительных путей обеспечивается гибкая структура приложения без жесткой привязки к абсолютным URL.

Лучшие практики при работе с относительными путями

  1. Использовать относительные пути для вложенных маршрутов — это упрощает переименование и перемещение маршрутов.
  2. Не смешивать абсолютные и относительные пути без необходимости — это снижает вероятность ошибок.
  3. Использовать ../ для возврата на родительский уровень — облегчает навигацию между уровнями вложенности.
  4. Сохранять единообразие: если большинство маршрутов внутри родителя относительные, все дочерние лучше делать относительными.
  5. Проверять работу useNavigate и <Link> при изменении структуры маршрутов — особенно важно при динамических параметрах.

Примеры комбинаций

<Route path="projects" element={<Projects />}>
  <Route path=":projectId" element={<ProjectDetails />}>
    <Route path="tasks" element={<Tasks />} />
    <Route path="settings" element={<ProjectSettings />} />
  </Route>
</Route>

Навигация внутри <ProjectDetails>:

<Link to="tasks">Задачи проекта</Link>          // /projects/:projectId/tasks
<Link to="settings">Настройки проекта</Link>   // /projects/:projectId/settings
<Link to="../">Вернуться к списку проектов</Link> // /projects

Относительные пути во вложенных маршрутах в React Router создают мощный инструмент для построения масштабируемых и читаемых приложений, обеспечивая компактную и удобную навигацию без лишнего дублирования URL.