Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Розбіжність HTML». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)Якщо після SSR клієнтський віртуальний DOM **не збігається точно** з HTML, який згенерував сервер, React виводить попередження про помилку гідрації в консоль і може **перерендерити частину дерева**, що спричиняє втрату стану або блимання інтерфейсу. **Ключове:** причина зазвичай у недетермінованому рендерингу - `Math.random()`, `Date.now()`, доступі до `window` до гідрації тощо.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Контекст: що таке гідрація Після 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, > незалежно від того, чи був він згенерований на сервері, чи на клієнті.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.