Роутинг связывает URL с тем, что видит пользователь: какой экран показать, какие данные ему нужны, пускать ли вообще. В React-стеке стандарт — React Router. Понять его модель (маршруты, вложенность, параметры, защита) — значит уметь собирать навигацию, которая масштабируется на десятки экранов.

Маршруты и вложенность

Маршрут сопоставляет путь компоненту. Маршруты вкладывают друг в друга: общий layout (шапка, навигация) — снаружи, конкретные экраны — внутри, через Outlet.

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

function AppLayout() {
  return (
    <div>
      <Header />
      <main><Outlet /></main>
    </div>
  );
}

function AppRoutes() {
  return (
    <Routes>
      <Route element={<AppLayout />}>
        <Route path="/products" element={<ProductList />} />
        <Route path="/products/:id" element={<ProductDetails />} />
      </Route>
    </Routes>
  );
}

Outlet — место, куда подставляется вложенный маршрут. Это та же композиция, что у компонентов: layout задаёт рамку, маршруты — содержимое. Вложенность держит навигацию структурной, а не плоским списком из полусотни путей.

Параметры и навигация

Динамическую часть пути (:id) достают через useParams; программный переход — через useNavigate.

function ProductDetails() {
  const { id } = useParams();
  const product = useProduct(id);     // TanStack Query по id
  // ...
}

function CreateButton() {
  const navigate = useNavigate();
  return <button onClick={() => navigate("/products/new")}>Создать</button>;
}

Параметр маршрута обычно становится частью ключа запроса (["product", id]) — URL и данные согласованы: меняется адрес — меняются данные.

Загрузка данных по маршруту

Есть два подхода. Первый — данные грузит компонент экрана через TanStack Query (как выше): просто и в одном инструменте для всего серверного состояния. Второй — data-router с loader-ами, где данные маршрута загружаются до отрисовки экрана. Для большинства приложений хватает первого; loader-ы полезны, когда важно не показывать экран без данных и убрать промежуточные состояния загрузки. Выбор — по потребности, без догмы.

Защищённые маршруты

Доступ к маршруту по аутентификации — обёртка, которая пускает или перенаправляет на вход. Это frontend-аналог guard: проверка на границе экрана.

function RequireAuth({ children }: { children: React.ReactNode }) {
  const user = useCurrentUser();
  if (!user) return <Navigate to="/login" replace />;
  return <>{children}</>;
}

<Route
  path="/account"
  element={<RequireAuth><Account /></RequireAuth>}
/>

Важно помнить границу: это удобство интерфейса, не безопасность. Реальную проверку прав делает backend на каждом запросе — клиент лишь не показывает то, чего пользователю не положено. Прятать кнопку без серверной проверки — дыра.

Где это в UCP

Роутинг — это карта продукта: какие экраны есть, как между ними двигаться, что доступно. Вложенность даёт структуру, параметры связывают URL с данными, защищённые маршруты — удобную (но не доверенную) границу доступа. Это позволяет продукт-инженеру держать навигацию растущего продукта осмысленной; а как всё это выглядит — вопрос стилизации.