Что такое hydration в React и какие ошибки hydration mismatch возникают?

MiddleReact · Frontend·Обновлено 31 августа 2026
Коротко
Hydration — это процесс, при котором React на клиенте прикрепляет обработчики событий и состояние к уже готовому HTML, полученному от сервера, вместо повторного построения DOM с нуля. Hydration mismatch — ошибка, возникающая, когда разметка, отрендеренная сервером, не совпадает с тем, что React получил бы при рендере на клиенте.

Что такое hydration

Hydration (гидратация) — механизм, с помощью которого React "оживляет" статический HTML, пришедший с сервера при SSR или SSG. Вместо того чтобы удалить существующую разметку и построить DOM заново, React проходит по уже отрендеренным узлам, сопоставляет их со своим виртуальным деревом и, если всё совпадает, просто навешивает обработчики событий и связывает узлы с внутренним состоянием компонентов.

Как это работает на практике

  • Сервер рендерит компоненты в HTML через renderToString или renderToPipeableStream.
  • Браузер сразу показывает готовую разметку — пользователь видит контент до загрузки JS, это улучшает FCP и LCP.
  • После загрузки бандла вызывается hydrateRoot (React 18+) вместо createRoot.
  • React проверяет соответствие DOM-дерева и того, что получилось бы при обычном клиентском рендере, и переиспользует существующие узлы.

Что такое hydration mismatch

Если результат серверного и клиентского рендера расходится, React обнаруживает несовпадение во время гидратации. В dev-режиме это выводит предупреждение в консоль вида "Hydration failed because the initial UI does not match what was rendered on the server". React пытается восстановить согласованность, отбрасывая часть серверной разметки и перерендеривая узел на клиенте — это может вызвать заметное "мигание" контента и лишнюю работу браузера.

Частые причины mismatch

  • Недетерминированные значения в рендере: Date.now(), Math.random(), new Date() — на сервере и клиенте они разные.
  • Обращение к window, localStorage, navigator прямо в теле компонента при первом рендере.
  • Форматирование дат и чисел, зависящее от локали или часового пояса окружения (сервер и браузер пользователя могут отличаться).
  • Паттерн typeof window !== 'undefined' для условного рендера — на сервере и клиенте условие даёт разный результат.
  • Невалидная вложенность HTML (<p> внутри <p>, <div> внутри <span>) — браузер молча исправляет такую разметку при парсинге, и итоговый DOM отличается от того, что построил сервер.
  • Расширения браузера, которые вставляют атрибуты в <body> до гидратации (классический пример — Grammarly).
  • Гонка данных: сервер и клиент получают данные в разное время, и ответ API успел измениться.

Как избежать mismatch

  • Не использовать источники недетерминированных значений в самом рендере — вычислять их в useEffect и обновлять состояние уже после монтирования.
  • Для контента, который обязан отличаться на клиенте (локальное время, значения из localStorage), рендерить на сервере нейтральную заглушку и подменять её в useEffect.
  • Точечно подавлять безопасные различия через suppressHydrationWarning (например, для метки времени), но не использовать это как способ скрыть реальные баги.
  • Следить за валидностью HTML-вложенности, особенно при использовании кастомных компонентов, которые рендерят блочные элементы.
  • Гарантировать, что данные для SSR и первого клиентского рендера идентичны — передавать initial state через props или дегидратированный кэш (например, React Query dehydrate/hydrate).

Итог

Hydration позволяет совместить быстрый первый рендер SSR с интерактивностью клиентского React, но требует, чтобы разметка на сервере и клиенте была детерминированной. Mismatch — почти всегда сигнал, что рендер зависит от окружения (время, случайность, доступность браузерных API), и лечится вынесением такой логики за пределы первого рендера.

Что хочет услышать интервьюер

Кандидат объясняет, что hydration переиспользует серверный HTML, а не перестраивает DOM заново

Понимание разницы между hydrateRoot и createRoot

Умение назвать конкретные причины mismatch (Date.now, window, невалидный HTML)

Знание практических способов избежать mismatch (useEffect, suppressHydrationWarning)

Понимание последствий mismatch: предупреждения, лишний перерендер, мигание UI

Пример: Причина mismatch: недетерминированное значение в рендере

// Плохо: Date.now() даёт разные значения на сервере и клиенте
function Timestamp() {
  return <span>{Date.now()}</span>;
}

// React выдаст предупреждение о hydration mismatch,
// потому что серверный HTML и клиентский рендер не совпадут

Пример: Исправление через useEffect

function Timestamp() {
  // На сервере и при первом клиентском рендере используем заглушку
  const [time, setTime] = useState<number | null>(null);

  useEffect(() => {
    // Значение выставляем уже после монтирования на клиенте
    setTime(Date.now());
  }, []);

  return <span>{time ?? '—'}</span>;
}

Пример: Точечное подавление ожидаемого различия

function LastVisit({ isoDate }: { isoDate: string }) {
  // Форматирование зависит от локали браузера пользователя,
  // поэтому сервер и клиент могут дать разный текст — это ожидаемо
  return (
    <time suppressHydrationWarning>
      {new Date(isoDate).toLocaleString()}
    </time>
  );
}

Типичные ошибки

Путают hydration с обычным клиентским рендером и не видят разницы в поведении React

Не могут назвать ни одной конкретной причины mismatch, кроме общих слов

Предлагают suppressHydrationWarning как универсальное решение для любых расхождений

Не знают, что обращение к window/localStorage в теле компонента при первом рендере ломает SSR

Считают, что невалидная HTML-вложенность не влияет на гидратацию

Лучшие курсы по теме

изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Feature-Sliced Design

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.5
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее