Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Звідки беруться помилки гідратації в React і як їх виправляти?

Гідратація - процес, коли React у браузері «підхоплює» HTML, згенерований на сервері: прив'язує обробники подій і стан до вже наявних елементів. React очікує, що перший рендер у браузері дасть точно такий самий результат, що й на сервері. Розбіжність - помилка гідратації.

Наслідки: React виводить помилку й перерендерює частину дерева на клієнті (повільніше, можливе «мигання»), а атрибути можуть лишитися невиправленими. Документація радить вважати розбіжності багами.

Найчастіші причини:

1. Значення, різні на сервері й клієнті:

<p>Згенеровано: {new Date().toLocaleTimeString()}</p>   // інший час
<p>{Math.random()}</p>
<p>{price.toLocaleString()}</p>                           // інша локаль чи часовий пояс

2. Перевірки середовища в рендері:

{typeof window !== 'undefined' && <MobileMenu />}   // на сервері немає, на клієнті є

3. Дані з браузера: localStorage, розмір вікна, тема з налаштувань системи - на сервері їх немає.

4. Некоректна вкладеність HTML: <p> всередині <p>, <div> у <p>, <a> у <a> - браузер «виправляє» розмітку при розборі, і дерево відрізняється від очікуваного.

5. Розширення браузера, що змінюють DOM до гідратації (перекладачі, менеджери паролів).

Як виправляти:

  • значення лише для клієнта - після монтування:
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);

return <p>Згенеровано: {mounted ? new Date().toLocaleTimeString() : '...'}</p>;

Перший рендер збігається з сервером, а одразу після гідратації - другий з клієнтськими даними. У Next.js - також dynamic(() => import(...), { ssr: false }) для компонентів, яким сервер узагалі не потрібен;

  • дати й числа - форматувати з явною локаллю й часовим поясом однаково на обох боках (Intl.DateTimeFormat('uk', { timeZone: 'Europe/Kyiv' })) або передавати вже відформатований рядок із сервера;
  • ідентифікатори - useId, а не лічильник чи Math.random();
  • неминуча розбіжність одного елемента (позначка часу) - suppressHydrationWarning на ньому. Діє лише на один рівень і не виправляє вміст - це запасний вихід, а не рішення;
  • тема без мигання - встановлювати клас на <html> вбудованим скриптом до гідратації і suppressHydrationWarning на <html>.

Діагностика: у режимі розробки React показує, у якому елементі й чим відрізнялися дерева; onRecoverableError у hydrateRoot дає змогу збирати ці помилки в моніторинг на продакшені.

Докладніше в документації: hydrateRoot

Схожі питання