Skip to main content

Розбіжність HTML

Контекст: що таке гідрація

Після SSR браузер отримує готовий HTML. Клієнтський JavaScript (React, Vue та ін.) потім виконує той самий рендер, щоб "прив'язати" логіку і події до вже існуючого DOM. Цей процес - hydration.

Щоб гідрація пройшла успішно:

Клієнтський віртуальний DOM повинен точно збігатися з HTML, який згенерував сервер.


Що відбувається при розбіжності

1. React намагається "зіставити" DOM

React порівнює наявний HTML (з сервера) з тим, що він очікує при клієнтському рендерингу.

Якщо відмінності незначні (наприклад, атрибут class або текст всередині елемента), React може спробувати мовчки виправити DOM. Якщо відмінності серйозні - React виведе попередження або навіть перерендерить частину дерева.


2. React видає помилку в консоль

Ти побачиш повідомлення на кшталт:

javascript
Warning: Text content did not match. Server: "42" Client: "43"

або

javascript
Warning: Hydration failed because the initial UI does not match what was rendered on the server.

Це означає: React очікував одне дерево, а отримав інше.


3. Можливі наслідки

СитуаціяЩо станеться
Невеликі відмінності (текст, атрибут)React тихо виправить DOM, але це може викликати "reflow" або блимання інтерфейсу
Суттєві відмінності (різна структура)React видалить старий HTML і перерендерить компонент заново
Масові розбіжностіВтрата стану, подвійне виконання ефектів, помилки логіки
У строгому режимі (React 18 StrictMode)React видає попередження і може скинути все дерево

Приклад

Сервер віддав:

javascript
<div id="root"> <p>Сьогодні: 17 жовтня</p> </div>

Клієнт відрендерив:

javascript
<div id="root"> <p>Сьогодні: 18 жовтня</p> </div>

React виявить розбіжність і покаже:

javascript
Warning: Text content did not match. Server: "Сьогодні: 17 жовтня" Client: "Сьогодні: 18 жовтня"

Користувач побачить коротке "блимання" контенту - React замінить текст після гідрації.


Основні причини помилок гідрації

1. Використання "нестабільних" значень

  • Math.random()
  • Date.now()
  • new Date()
  • UUID / випадкові ключі
  • випадкові id (наприклад, id={Math.random()})

Рішення: Генеруй їх на сервері заздалегідь і передавай через props.


2. Код, залежний від браузера

На сервері немає window, document, navigator, localStorage тощо.

Неправильно:

javascript
const width = window.innerWidth; // Помилка при SSR

Правильно:

javascript
const [width, setWidth] = useState(0); useEffect(() => setWidth(window.innerWidth), []);

3. Умовний рендеринг, залежний від середовища

Якщо компонент рендериться по-різному залежно від:

  • розміру екрана,
  • користувацької сесії,
  • локалі,
  • cookie / theme mode.

Приклад:

javascript
{typeof window !== "undefined" && <Sidebar />}

На сервері window немає → Sidebar не відрендериться. На клієнті window є → Sidebar з'явиться → mismatch.

Рішення: Рендерити з тими самими умовами або використовувати useEffect для клієнтського коду.


4. Розбіжність даних між сервером і клієнтом

Якщо SSR довантажує одні дані, а клієнт повторно запитує інші → розбіжність HTML.

Рішення:

  • Передавати initialData з SSR на клієнт через __INITIAL_STATE__ або pageProps.
  • Використовувати однакову логіку завантаження даних.

Як React реагує (React 18+)

ВерсіяПоведінка
React 17 і нижчеМовчки виправляв відмінності (часто спричиняв баги)
React 18Явно попереджає в консолі і може скинути DOM
React 18 (StrictMode)Перевіряє подвійним рендером, щоб виявити розбіжності

Як уникнути mismatches

  1. Використовуй детерміновані дані при SSR.
  2. Не рендери елементи, залежні від браузера, до гідрації.
  3. Передавай на клієнт усі initial props/data.
  4. Перевіряй SSR-рендер через ReactDOMServer.renderToString() локально.
  5. Вмикай StrictMode - він допомагає виявити помилки гідрації.

Висновок

Якщо HTML, згенерований на сервері, не збігається з клієнтським:

  • React видає попередження або помилку гідрації.
  • Може відбутися перерендер, втрата стану або блимання інтерфейсу.
  • Це часто пов'язано з недетермінованим рендерингом (дати, рандом, window тощо).

Ідеальна SSR-гідрація = той самий HTML, незалежно від того, чи був він згенерований на сервері, чи на клієнті.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.