Гидратация (hydration) — процесс привязки уже отрендеренного на сервере HTML к React-компонентам на клиенте. В контексте React Router гидратация играет критическую роль в обеспечении маршрутизации и сохранении состояния навигации при серверном рендеринге (SSR).
Для начала необходимо создать маршруты и настроить серверный рендеринг. Пример маршрутов:
import { createRoutesFromElements, Route } from "react-router-dom";
import App from "./App";
import Home from "./pages/Home";
import About from "./pages/About";
export const routes = createRoutesFromElements(
}>
} />
} />
);
На сервере используется renderToString или
renderToPipeableStream (в зависимости от версии React) для
генерации HTML:
import { renderToString } from "react-dom/server";
import { StaticRouter } from "react-router-dom/server";
import { routes } from "./routes";
import { matchRoutes } from "react-router-dom";
function handleRequest(req, res) {
const matches = matchRoutes(routes, req.url);
const html = renderToString(
);
res.send(`
SSR React Router
${html}
`);
}
Ключевой момент: StaticRouter
используется только на сервере для сопоставления URL с маршрутами. Он не
поддерживает клиентскую навигацию.
После получения отрендеренного на сервере HTML необходимо подключить
React-компоненты и сделать их интерактивными. Для этого используется
hydrateRoot:
import { hydrateRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { App } from "./App";
const container = document.getElementById("root");
hydrateRoot(
container,
);
Особенности:
BrowserRouter обеспечивает полноценную клиентскую
навигацию.hydration mismatch).При SSR часто используется предзагрузка данных для маршрутов. React
Router предоставляет функции loader для этого:
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { Home } from "./pages/Home";
const router = createBrowserRouter([
{
path: "/",
element: ,
loader: async () => {
const data = await fetch("/api/data").then(res => res.json());
return data;
}
}
]);
hydrateRoot(
document.getElementById("root"),
);
Преимущества использования loader при
гидратации:
Часто при гидратации возникают ошибки из-за разницы в рендеринге серверного и клиентского HTML. Основные причины:
window или других браузерных API на
сервере.Методы устранения:
useEffect для клиентских побочных
эффектов.suppressHydrationWarning
для компонентов, которые могут различаться.React Router позволяет комбинировать гидратацию с ленивой загрузкой
компонентов через React.lazy:
import { lazy, Suspense } from "react";
const About = lazy(() => import("./pages/About"));
Loading... Важно: при SSR необходимо обеспечить, чтобы
серверный HTML содержал начальный вид страницы до ленивой загрузки. Для
этого часто используют loadable-components или аналогичные
библиотеки, которые интегрируются с React Router.
После успешной гидратации маршруты становятся интерактивными:
Link для навигации без перезагрузки
страницы.useNavigate позволяет программно изменять URL.location, params)
синхронизировано между сервером и клиентом.Пример навигации:
import { useNavigate } from "react-router-dom";
function Button() {
const navigate = useNavigate();
return ;
}
Сервер:
StaticRouter.loader или аналогом.Клиент:
hydrateRoot.BrowserRouter для интерактивной
навигации.RouterProvider и loader для
поддержания синхронизации данных.Эта схема обеспечивает плавный переход от серверного рендеринга к полноценной клиентской маршрутизации без перезагрузки страницы.