> В чем отличие useEffect от useLayoutEffect в React (React)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Точка, Soft_Media_Group, EvApps, VK, Aston, IT-One, Софт Медиа Групп, EPAM, ПСБ, intelsy, Black Wall Group (BWG), Сбер
Стек: React
> Пример ответа
Короткий ответ
Основное отличие - время выполнения. useEffect запускается асинхронно после того, React отрисовал DOM и браузер выполнил paint. useLayoutEffect запускается синхронно сразу после обновления DOM, но до того, как браузер показал изменения пользователю. Это делает useLayoutEffect подходящим для операций, которые должны быть выполнены до отрисовки, например, чтение layout или синхронные мутации DOM.
Подробное объяснение
Оба хука принимают функцию с эффектом и массив зависимостей. Разница в фазе выполнения в React lifecycle:
-
useEffect: выполняется после того, как React зафиксировал изменения в DOM и браузер отобразил их (commit phase → paint). Это асинхронная операция, не блокирующая визуализацию. Подходит для побочных эффектов, не влияющих на layout: запросы к API, подписки на события, логирование. -
useLayoutEffect: выполняется синхронно сразу после того, как React обновил DOM, но до того, как браузер выполнил paint. Это блокирует отрисовку до завершения эффекта. Подходит для операций, которые должны быть выполнены до того, как пользователь увидит изменения: измерение размеров элементов, синхронное изменение стилей, анимации на основе layout.
React гарантирует, что все useLayoutEffect из одного дерева компонентов выполнятся последовательно, прежде чем браузер сможет отрисовать кадр. Это может привести к задержкам при рендеринге, если эффект тяжёлый.
На практике
- Используйте
useEffectпо умолчанию для большинства побочных эффектов. Это безопаснее и не блокирует UI. - Используйте
useLayoutEffectтолько когда вам нужно:- Прочитать layout элемента (например,
getBoundingClientRect,offsetHeight) и сразу применить изменения, чтобы избежать визуального мерцания. - Синхронно обновить DOM перед отрисовкой (например, позиционирование тултипа, скролл к элементу).
- Выполнить эффект, который должен быть завершён до того, как пользователь увидит результат (например, анимация входа).
- Прочитать layout элемента (например,
Если вы используете useLayoutEffect на сервере (SSR), React выдаст предупреждение, так как на сервере нет браузерного API. В таких случаях нужно либо переключиться на useEffect, либо использовать useIsomorphicLayoutEffect (кастомный хук, который выбирает useLayoutEffect на клиенте и useEffect на сервере).
Пример кода
JSXimport { useState, useRef, useEffect, useLayoutEffect } from 'react';function Tooltip({ text }) {const [tooltipWidth, setTooltipWidth] = useState(0);const tooltipRef = useRef(null);// useLayoutEffect - читаем layout до отрисовкиuseLayoutEffect(() => {if (tooltipRef.current) {const width = tooltipRef.current.offsetWidth;setTooltipWidth(width);}}, [text]);// useEffect - подписка на событие после отрисовкиuseEffect(() => {const handleResize = () => console.log('Window resized');window.addEventListener('resize', handleResize);return () => window.removeEventListener('resize', handleResize);}, []);return (<divref={tooltipRef}style={{ position: 'absolute', left: `calc(50% - ${tooltipWidth / 2}px)` }}>{text}</div>);}
Как отвечать на собеседовании
Начните с ключевого отличия: время выполнения относительно paint. Приведите конкретный сценарий, где useLayoutEffect необходим (например, измерение DOM), и объясните, почему useEffect не подходит (будет мерцание). Упомяните, что useLayoutEffect блокирует отрисовку, поэтому его следует использовать только при необходимости. Если спросят про SSR - скажите про useIsomorphicLayoutEffect. Держите ответ структурированным: сначала разница, потом когда что применять, потом пример.
Что проверяет интервьюер
- Понимание React lifecycle и фазы commit.
- Умение выбирать правильный хук под задачу.
- Осознание trade-off между производительностью и корректностью UI.
- Знание ограничений (SSR, блокировка paint).
- Способность объяснить разницу простыми словами и с примерами.
Типичные ошибки
- Использовать
useLayoutEffectдля всех эффектов "на всякий случай" - это ухудшает производительность. - Путать порядок выполнения:
useLayoutEffectвыполняется доuseEffectв одном компоненте. - Пытаться читать layout в
useEffectи обновлять состояние - это вызывает дополнительный рендер и мерцание. - Не учитывать SSR:
useLayoutEffectвызовет warning на сервере. - Думать, что
useLayoutEffectвыполняется до монтирования компонента - он выполняется после монтирования, но до paint.
> Похожие задачи по frontend
Как работает useRef хук в React и для чего он используется
Как работает жизненный цикл React-компонентов
Как реализовать React компонент с текстовым полем для запроса к API, отображением результатов, индикатором загрузки и обработкой ошибок?
Почему React работает быстро, как устроен виртуальный DOM и процесс обновления?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью