Що робить useLayoutEffect() при SSR?
Нагадаємо: що робить useLayoutEffect() у клієнтському React
useLayoutEffect() - це "синхронний" аналог useEffect():
| Хук | Коли спрацьовує |
|---|---|
useEffect() | вже після того, як браузер намалював DOM (асинхронно) |
useLayoutEffect() | одразу після того, як React оновив DOM, але до відмальовки екрана |
Тобто
useLayoutEffect()дозволяє:
- виміряти розміри елементів,
- синхронно змінити layout,
- або виконати DOM-мутації до того, як користувач побачить екран.
Що відбувається при SSR
При Server-Side Rendering React не має доступу до DOM.
- Немає
window, - немає
document, - немає реальних елементів.
А отже, будь-які DOM-операції всередині useLayoutEffect() неможливі.
Тому React взагалі не викликає цей хук на сервері.
Поведінка useLayoutEffect() в SSR
На сервері:
- React повністю ігнорує всі
useLayoutEffect()(іuseEffect()теж). - Тобто код всередині не виконається взагалі.
- Компонент рендериться "чисто" - лише повертає JSX -> HTML.
На клієнті (після гідрації):
- React виконає
useLayoutEffect()один раз, коли гідрація завершиться і DOM уже доступний. - Якщо в хук закладені побічні ефекти, вони спрацюють лише після того, як HTML вже з'явився в браузері.
Можлива проблема - попередження в консолі
Якщо ти використовуєш useLayoutEffect() всередині компонента, що рендериться і на сервері, і на клієнті, React може вивести попередження:
Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format.або
Warning: useLayoutEffect is not supported during server rendering.Це не помилка, а попередження: React просто повідомляє, що твій layout-ефект буде проігнорований під час SSR.
Як уникнути проблем
Варіант 1. Замінити useLayoutEffect на useEffect, якщо можна
Якщо твій код не залежить від точного вимірювання DOM, краще просто використати useEffect:
useEffect(() => {
console.log('Безпечно для SSR');
}, []);Варіант 2. Обгортати виклик у перевірку середовища
Якщо тобі все-таки потрібен useLayoutEffect (наприклад, для canvas, вимірювань і анімацій),
можна безпечно визначити "універсальний" хук:
import { useLayoutEffect, useEffect } from 'react';
// Безпечний хук для SSR
export const useIsomorphicLayoutEffect =
typeof window !== 'undefined' ? useLayoutEffect : useEffect;Тепер можна писати:
useIsomorphicLayoutEffect(() => {
const rect = ref.current.getBoundingClientRect();
console.log(rect);
}, []);На сервері виконається useEffect (тобто нічого не станеться),
а в браузері - справжній useLayoutEffect.
Варіант 3. Виконувати DOM-залежний код лише після гідрації
const [hydrated, setHydrated] = useState(false);
useEffect(() => {
setHydrated(true);
}, []);
if (!hydrated) return null;
useLayoutEffect(() => {
// Цей код виконається лише на клієнті, після гідрації
}, []);Резюме
| Середовище | Що робить useLayoutEffect() |
|---|---|
| Сервер (SSR) | Повністю ігнорується - не викликається, DOM недоступний |
| Клієнт (після гідрації) | Виконується синхронно після вставки HTML у DOM |
| Якщо використовується в SSR-компоненті | Може викликати попередження, але не помилку |
| Рішення | Використати useIsomorphicLayoutEffect або useEffect |
Ключова думка
useLayoutEffectне працює на сервері. React просто пропускає його під час SSR, а виконує лише після того, як HTML уже відрендерений і "оживлений" на клієнті.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.