Вопрос проверяет понимание проблемы несоответствия между серверным и клиентским рендерингом в React и способов её предотвращения для обеспечения стабильности приложения.
Hydration mismatch — это критическая ошибка в React-приложениях, использующих серверный рендеринг (SSR). Она возникает в момент "гидратации", когда React на клиенте пытается "оживить" статический HTML, полученный с сервера, добавляя к нему обработчики событий и состояние. Если DOM-дерево, созданное клиентом, не совпадает побитово с серверным HTML, React не может корректно сопоставить узлы, что приводит к ошибке и полной перерисовке всего поддерева на клиенте, сводя на нет преимущества SSR.
Ключевой принцип — гарантировать, что начальный рендер компонента даёт абсолютно одинаковый результат и на сервере, и на клиенте.
Рассмотрим компонент, который показывает текущее время, но должен избежать mismatch.
import { useEffect, useState } from 'react';
function TimeComponent() {
// 1. Инициализируем состояние одинаково для сервера и клиента
const [currentTime, setCurrentTime] = useState(null);
useEffect(() => {
// 2. Код, зависящий от браузера, запускаем ТОЛЬКО на клиенте
setCurrentTime(new Date().toLocaleTimeString());
}, []); // Пустой массив зависимостей = запуск только после монтирования
// 3. На сервере и при первой отрисовке на клиенте показываем заглушку
return (
Текущее время: {currentTime || 'Загрузка...'}
);
}
export default TimeComponent;В этом примере на сервере и при самой первой отрисовке на клиенте (во время гидратации) компонент выведет "Загрузка...". Только после монтирования в `useEffect` обновится состояние и покажется реальное время. Так как первоначальный HTML идентичен, mismatch не произойдёт.
Hydration mismatch — это проблема целостности данных и логики рендеринга между сервером и клиентом. Избегать её необходимо для сохранения преимуществ SSR: скорости первой загрузки и SEO. Основной подход — чёткое разделение кода: всё, что должно быть в начальном HTML, должно рендериться одинаково, а любая клиент-специфичная логика должна быть изолирована в `useEffect` или инициирована только после гидратации.