createStaticRouter

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


Импорт и базовое использование

Для начала необходимо импортировать функцию:

import { createStaticRouter, RouterProvider } from "react-router-dom/server";

createStaticRouter принимает два аргумента:

  1. routes — массив объектов маршрутов.
  2. options — объект дополнительных параметров (необязательный).

Простейший пример:

const routes = [
  {
    path: "/",
    element: <HomePage />,
  },
  {
    path: "/about",
    element: <AboutPage />,
  },
];

const staticRouter = createStaticRouter(routes);

<RouterProvider router={staticRouter} />

Здесь RouterProvider принимает созданный статический маршрутизатор и обеспечивает рендеринг компонентов в зависимости от URL.


Структура маршрутов

Каждый маршрут описывается объектом со следующими ключами:

  • path — строка с URL маршрута.
  • element — React-компонент, который будет отображаться.
  • children — массив дочерних маршрутов (для вложенных путей).
  • errorElement — компонент для отображения ошибок маршрута.
  • loader — асинхронная функция для предварительной загрузки данных.
  • action — асинхронная функция для обработки форм или других действий.

Пример вложенных маршрутов:

const routes = [
  {
    path: "/",
    element: <Layout />,
    children: [
      {
        path: "",
        element: <HomePage />,
      },
      {
        path: "profile",
        element: <ProfilePage />,
      },
    ],
  },
];

В этом примере Layout рендерится всегда, а содержимое меняется в зависимости от дочернего маршрута.


Использование loader для предварительной загрузки данных

Статический маршрутизатор позволяет загружать данные перед рендерингом страницы:

const routes = [
  {
    path: "/users/:id",
    element: <UserPage />,
    loader: async ({ params }) => {
      const response = await fetch(`https://api.example.com/users/${params.id}`);
      return response.json();
    },
  },
];

Внутри компонента можно использовать хук useLoaderData:

import { useLoaderData } from "react-router-dom";

function UserPage() {
  const user = useLoaderData();
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

Обработка ошибок с errorElement

Если loader или action выбрасывают ошибку, можно отобразить специальный компонент:

const routes = [
  {
    path: "/users/:id",
    element: <UserPage />,
    loader: async ({ params }) => {
      const response = await fetch(`https://api.example.com/users/${params.id}`);
      if (!response.ok) throw new Error("Пользователь не найден");
      return response.json();
    },
    errorElement: <ErrorPage />,
  },
];

Компонент ErrorPage получит объект ошибки через хук useRouteError.


Параметры и опции createStaticRouter

Второй аргумент функции позволяет задавать дополнительные настройки:

  • basename — базовый путь для всех маршрутов, если приложение не на корневом уровне.
  • future — включение экспериментальных возможностей React Router.
  • hydration — настройка для гидратации статического HTML на клиенте.

Пример с базовым путем:

const staticRouter = createStaticRouter(routes, { basename: "/app" });

Интеграция с серверным рендерингом

createStaticRouter идеально подходит для SSR:

import express from "express";
import { renderToString } from "react-dom/server";
import { RouterProvider, createStaticRouter } from "react-router-dom/server";

const app = express();

app.get("*", async (req, res) => {
  const router = createStaticRouter(routes, { initialEntries: [req.url] });
  const html = renderToString(<RouterProvider router={router} />);
  res.send(`<!DOCTYPE html><html><body>${html}</body></html>`);
});

app.listen(3000);

Здесь initialEntries задаёт URL для рендеринга, что позволяет серверу корректно отобразить нужную страницу без клиентской навигации.


Особенности и преимущества

  • Полный контроль над деревом маршрутов без зависимости от браузерного History API.
  • Возможность предзагрузки данных на сервере через loader.
  • Обработка ошибок на уровне маршрутов через errorElement.
  • Поддержка вложенных маршрутов и базовых путей (basename).
  • Полная совместимость с гидратацией React-приложений на клиенте.

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