В чем разница между useEffect и useLayoutEffect?
Хуки
Оба хука выполняют побочные эффекты, у них одинаковая сигнатура, но разное время выполнения относительно отрисовки браузера.
useEffect
- Выполняется асинхронно после того, как браузер отрисовал кадр.
- Не блокирует отрисовку — пользователь сразу видит обновлённый UI.
- Подходит для 95% случаев: запросы к серверу, подписки, логирование, работа с localStorage.
useLayoutEffect
- Выполняется синхронно после изменения DOM, но до отрисовки кадра браузером.
- Блокирует отрисовку: пока эффект не завершится, пользователь ничего не увидит.
- Нужен, когда эффект читает layout (размеры, позиции элементов) и синхронно меняет DOM, иначе будет видимое «мигание».
Пример, где нужен useLayoutEffect
const Tooltip = ({ targetRef }) => {
const [position, setPosition] = useState({ top: 0, left: 0 });
useLayoutEffect(() => {
const rect = targetRef.current.getBoundingClientRect();
setPosition({ top: rect.bottom, left: rect.left });
}, [targetRef]);
// с useEffect тултип на один кадр отрисовался бы в точке (0, 0)
return <div style={position}>...</div>;
};Нюансы
- Порядок: рендер → коммит в DOM → useLayoutEffect → отрисовка браузера → useEffect.
- Тяжёлая логика в useLayoutEffect напрямую бьёт по отзывчивости интерфейса.
- При SSR useLayoutEffect не выполняется на сервере (до React 19 React ещё и выдавал предупреждение, в React 19 его убрали).
Коротко для собеседования
useEffect срабатывает после отрисовки и не блокирует её; useLayoutEffect — синхронно до отрисовки. По умолчанию использовать useEffect; useLayoutEffect — только когда нужно измерить или синхронно поправить DOM до того, как пользователь увидит кадр (позиционирование, предотвращение мигания).