В каком порядке отрабатывают логи и рендер при использовании useEffect и useLayoutEffect с пустым массивом зависимостей в React
Что проверяют
Понимаете ли вы фазы работы React: рендер, коммит в DOM, отрисовку браузером, и где в них встают два эффекта. Следом часто спрашивают, почему в разработке логи печатаются дважды и когда useLayoutEffect действительно нужен.
Как отвечать
Порядок при монтировании компонента с обоими хуками и пустым массивом зависимостей:
- рендер: React вызывает функцию компонента, срабатывает
console.logв её теле. DOM ещё не тронут; - коммит: React вносит изменения в DOM;
useLayoutEffect: выполняется синхронно сразу после коммита, до того как браузер нарисует кадр. Здесь меряют элемент черезgetBoundingClientRectи правят состояние: повторный рендер тоже пройдёт до отрисовки, и мигания не будет;- отрисовка: браузер рисует экран;
useEffect: обычно выполняется после отрисовки и не блокирует её. Место для запросов, подписок, таймеров.
Итог в консоли: «render», «layout effect», «effect». С пустым массивом эффекты больше не повторяются, а их функции очистки вызовутся при размонтировании.
При вложенности эффекты идут от детей к родителю: сначала layout-эффекты ребёнка, потом родителя, а после отрисовки обычные эффекты в том же порядке.
Два уточнения, которые отличают сильный ответ:
StrictMode: в режиме разработки React вызывает тело компонента дважды, а затем монтирует, размонтирует и снова монтирует компонент, поэтому эффекты отработают дважды с очисткой между ними. В продакшен-сборке этого нет;- взаимодействие: если обновление вызвано кликом или вводом, React может выполнить
useEffectещё до отрисовки. Гарантировано только, что эффект идёт после коммита.
При SSR на сервере не выполняется ни один из эффектов, оба сработают только в браузере после гидратации.
Где спотыкаются
Говорят, что useLayoutEffect срабатывает до рендера. Он всегда идёт после рендера и после изменения DOM, раньше только отрисовки браузером.
Путают рендер React с отрисовкой браузера и называют оба действия одним словом.
Удивляются двойным логам и «чинят» их флагом в useRef, хотя это поведение StrictMode, которое помогает найти эффекты без очистки.