В чем разница между useEffect и useLayoutEffect

Ответ

useEffect и useLayoutEffect выполняют схожие задачи, но различаются временем выполнения:

  • useEffect вызывается асинхронно после рендера и отрисовки компонента в DOM. Подходит для сайд-эффектов, не требующих синхронного обновления (запросы, подписки).

  • useLayoutEffect вызывается синхронно после рендера, но перед отрисовкой в браузере. Используется, когда нужно измерить DOM или внести изменения до визуального отображения (например, скролл, анимации).

useEffect(() => {
  console.log("Асинхронный эффект");
}, []);

useLayoutEffect(() => {
  console.log("Синхронный эффект (перед отрисовкой)");
}, []);

⚠️ useLayoutEffect может блокировать отрисовку, если содержит тяжелые вычисления.

Ответ 18+ 🔞

Давай разберём эту парочку, а то они как близнецы-братья, только один тихий и спокойный, а второй — торопыга, который всё ломает.

Вот смотри, есть у тебя useEffect. Нормальный такой хуёк, воспитанный. Компонент отрендерился, браузер его на экран вывел, все довольны, красота. И только потом, тихонечко, асинхронно, подкрадывается наш эффект и делает свои дела: данные подтягивает, подписки вешает. Никого не дергает, не тормозит. Красота!

useEffect(() => {
  console.log("Я как хороший гость — приду, когда всё готово.");
}, []);

А теперь его братан-близнец — useLayoutEffect. Это тот самый родственник, который врывается в квартиру, пока ты ещё дверь открываешь. Компонент только-только посчитался (рендер), но браузер ещё даже пиксели на экран не вывел! А этот уж тут как тут — синхронно, с ноги в дверь, и начинает своё: DOM мерять, стили перекрашивать, скролл прыгать. Всё ДО того, как пользователь что-то увидит.

useLayoutEffect(() => {
  console.log("Я уже тут! Быстро давай сюда DOM, мне его щупать надо!");
}, []);

И в этом, блядь, вся соль! Если в useLayoutEffect запихнуть какую-нибудь тягомотину — вычисления овердохуищные, циклы бесконечные — то браузер просто повиснет, ждёт, пока этот торопыга всё своё говно сделает. Пользователь будет смотреть на белый экран и думать: "Ну что, опять эти фронтендеры ебутся?"

Короче, правило простое, как три копейки:

  1. useEffect — для 99% случаев. Запросы, подписки, таймеры — всё, что может подождать микросекунду, пока картинка нарисуется.
  2. useLayoutEffect — только когда без этого нихуя. Когда тебе критически нужно что-то поменять в DOM (например, твой тултип позицию посчитать) до того, как юзер моргнёт. Иначе будет дергание, прыгание — пиздец короче.

Запомнил? useEffect — после рисования, useLayoutEffect — до. А то перепутаешь — и волнение ебать, и терпения ноль ебать у всех пользователей.