Миграция с версии 5 на 6

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

Компонент Switch заменён на Routes

В версии 5 маршруты группировались внутри компонента Switch, который рендерил первый совпавший маршрут. В v6 Switch удалён и заменён на Routes. Основные особенности новой структуры:

import { Routes, Route } from 'react-router-dom';

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/about" element={<About />} />
</Routes>
  • Ключевой момент: теперь вместо component или render используется element, который принимает JSX.
  • Поведение маршрутов: маршруты автоматически сопоставляются с точным путём, точное совпадение (exact) больше не нужно.

Работа с вложенными маршрутами

В v6 вложенные маршруты стали более интуитивными. Родительский маршрут может содержать дочерние через элемент Route с массивом children.

<Routes>
  <Route path="/dashboard" element={<Dashboard />}>
    <Route path="analytics" element={<Analytics />} />
    <Route path="settings" element={<Settings />} />
  </Route>
</Routes>
  • Дочерние маршруты рендерятся внутри компонента родителя через <Outlet />.
  • <Outlet /> заменяет необходимость ручного вложения props.children.
function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      <Outlet />
    </div>
  );
}

Навигация с помощью useNavigate

Хук useHistory из v5 заменён на useNavigate. Он возвращает функцию для программной навигации.

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

function ProfileButton() {
  const navigate = useNavigate();
  
  return (
    <button onCl ick={() => navigate('/profile')}>
      Перейти в профиль
    </button>
  );
}
  • Параметры можно передавать через state: navigate('/profile', { state: { from: 'dashboard' } }).
  • Для замены текущего маршрута используется второй аргумент { replace: true }.

Работа с параметрами маршрутов

Хук useParams сохраняет своё назначение, но теперь чаще применяется в сочетании с вложенными маршрутами.

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

function UserDetail() {
  const { id } = useParams();
  return <div>Пользователь: {id}</div>;
}
  • Для более сложных маршрутов рекомендуется комбинировать useParams с useLocation и useNavigate.

Обработка редиректов

Вместо компонента <Redirect> теперь используется <Navigate>.

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/old-path" element={<Navigate to="/new-path" replace />} />
</Routes>
  • replace предотвращает добавление новой записи в историю.
  • <Navigate> может использоваться и внутри JSX как программный редирект через рендер.

Старые компоненты <Link> и <NavLink> остались, но поведение некоторых пропсов изменилось:

  • activeClassName убран, вместо него используется функция className, принимающая объект isActive.
<NavLink
  to="/about"
  className={({ isActive }) => (isActive ? 'active' : '')}
>
  О нас
</NavLink>

Переход с exact и strict

  • Точный матч теперь по умолчанию. Атрибуты exact и strict удалены.
  • Упрощается логика сопоставления маршрутов, особенно в комбинации с вложенностью.

Изменения в ленивой загрузке

Использование React.lazy и Suspense остаётся прежним, но синтаксис с v6 более удобен при объединении с маршрутизацией:

const About = React.lazy(() => import('./About'));

<Routes>
  <Route path="/about" element={
    <Suspense fallback={<div>Загрузка...</div>}>
      <About />
    </Suspense>
  } />
</Routes>
  • Позволяет разделять код по маршрутам без изменения логики навигации.

Итоговые рекомендации при миграции

  • Все маршруты переводятся на использование Routes и element.
  • Вложенные маршруты оформляются через children и <Outlet />.
  • Программная навигация через useNavigate, редиректы через <Navigate>.
  • Удаляются устаревшие атрибуты exact, strict, activeClassName.
  • Переход на новый API упрощает поддержку кода и устраняет неоднозначности, связанные с порядком сопоставления маршрутов.

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