Пошук уроків, статей та іншого контенту
Сервер надсилає готовий HTML, але сторінка стає інтерактивною лише після hydration — розбираємось, що це за процес і чому він іноді ламається.
Коли сторінку рендерить сервер (Server Components/SSR у Next.js — стаття «SSR, SSG та ISR у Next.js»), браузер спочатку отримує готовий HTML і показує його користувачу майже миттєво. Але цей HTML — статичний: кнопки поки що не реагують на клік, поле вводу не оновлює стан. Щоб сторінка стала інтерактивною, React має «оживити» вже наявний DOM — цей процес називається hydration (гідратація).
На відміну від звичайного рендеру в браузері (client-side rendering), де React будує DOM-дерево з нуля, при гідратації React отримує вже готове DOM-дерево (те саме, що прийшло з сервера як HTML) і прикріплює до нього обробники подій та внутрішній стан, не перестворюючи самі DOM-вузли. React проходить по дереву компонентів і зіставляє кожен елемент із відповідним вузлом уже наявного DOM — якщо структура збігається, це швидше, ніж рендерити з нуля вдруге.
1. Сервер рендерить компоненти → HTML → надсилається браузеру
2. Браузер показує HTML одразу (швидкий перший показ, ще не інтерактивний)
3. JavaScript-бандл довантажується й виконується
4. React "гідратує" наявний DOM: прикріплює обробники подій, ініціалізує стан
5. Сторінка стає повністю інтерактивноюReact очікує, що HTML, який він отримує від сервера, і те, що він сам відрендерив би на клієнті з тими самими даними, — однакові. Якщо вони різняться (hydration mismatch), React виводить попередження в консоль і в багатьох випадках відкидає серверний HTML, перерендерюючи вузол на клієнті — це і повільніше, і може призвести до помітного «блимання» контенту.
Значення, що залежать від часу виконання: new Date(), Math.random(), Date.now() — на сервері й клієнті виконуються в різний момент і дають різний результат.
Звернення до браузерних API під час рендеру (window, localStorage, navigator) — на сервері цих об'єктів просто не існує, тож така спроба або впаде з помилкою, або (у Client Component) відрендерить інший вміст, ніж очікує сервер.
Локале- чи часовий-пояс-залежне форматування дат/чисел — сервер і браузер користувача можуть мати різні налаштування локалі.
Розширення браузера, що модифікують DOM ще до гідратації (наприклад, деякі менеджери паролів додають атрибути до <input>) — React бачить DOM, що вже відрізняється від того, що він сам згенерував би.
Для контенту, що свідомо має відрізнятись між сервером і клієнтом (наприклад, локальний час користувача), React надає атрибут suppressHydrationWarning для конкретного вузла — явний, задокументований виняток, а не спосіб «заглушити» справжні помилки в інших місцях.
У Next.js App Router компоненти за замовчуванням — Server Components: вони виконуються лише на сервері, їхній JavaScript-код узагалі не потрапляє в бандл браузера, тож для них немає ні гідратації, ні клієнтського стану. Гідратація стосується лише Client Components (позначених "use client") — саме тому винесення інтерактивності в якомога менші, ізольовані Client Components зменшує обсяг JavaScript, який потрібно довантажити й гідрувати.
Читати window чи localStorage прямо в тілі функції компонента під час першого рендера — на сервері (і під час самого першого клієнтського рендера, до useEffect) цей код або впаде, або дасть інший результат, ніж очікує React; такі звернення варто виносити в useEffect, який виконується вже після гідратації.
Ігнорувати попередження про hydration mismatch у консолі як «просто варнінг» — воно вказує на реальну розбіжність контенту, яка в проді може проявлятись як помітне перемальовування сторінки для реальних користувачів.
Плутати «сторінка показалась» із «сторінка інтерактивна» — швидкий перший показ HTML не означає, що кнопки вже клікабельні; для великих бандлів проміжок між цими двома моментами може бути помітним.
Hydration — це процес, у якому React прикріплює обробники подій і стан до вже наявного, надісланого сервером HTML, замість того щоб будувати DOM з нуля. Він працює швидко й непомітно, доки HTML із сервера точно збігається з тим, що React відрендерив би сам — будь-яка розбіжність (час виконання, браузерні API, локаль) призводить до mismatch-попереджень і зайвого перерендеру. Server Components у Next.js взагалі не потребують гідратації, оскільки їхній код ніколи не потрапляє в браузер.