Гідратація - процес, коли 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 дає змогу збирати ці помилки в моніторинг на продакшені.