PassFront
  1. PassFront
  2. База знаний
  3. Хуки

useEffect выполняется синхронно или асинхронно?

Хуки

Сам колбэк useEffect — обычная синхронная функция, но вызывается он асинхронно относительно рендера: после того как изменения применены к DOM и браузер отрисовал кадр.

Порядок событий

рендер (вызов компонента)
→ commit (правки DOM)
→ браузер отрисовывает кадр
→ useEffect

Поэтому эффект не блокирует отрисовку: пользователь видит обновлённый UI, даже если в эффекте тяжёлая работа. Для сравнения, useLayoutEffect вызывается синхронно между коммитом и отрисовкой — блокируя кадр.

Проверка на практике

useEffect(() => {
  console.log('effect');        // третьим
});

useLayoutEffect(() => {
  console.log('layout effect'); // вторым
});

console.log('render');          // первым

Асинхронный код внутри эффекта

Сам колбэк не может быть async (он обязан вернуть cleanup-функцию или undefined, а async возвращает Promise). Асинхронность оформляется внутри:

useEffect(() => {
  let cancelled = false;

  (async () => {
    const data = await loadData(id);
    if (!cancelled) setData(data);
  })();

  return () => { cancelled = true; };
}, [id]);

Нюансы

  • «Асинхронно» здесь означает «не в потоке рендера», а не setTimeout: React планирует эффекты сам, обычно сразу после отрисовки.
  • Если в эффекте синхронно вызвать setState, React может выполнить повторный рендер до показа кадра — отсюда возможные «двойные» рендеры при неправильной работе с состоянием в эффектах.

Коротко для собеседования

useEffect выполняется асинхронно относительно рендера — после коммита в DOM и отрисовки кадра, не блокируя её (в отличие от синхронного useLayoutEffect). Сам колбэк — синхронная функция: async напрямую нельзя, асинхронный код оформляется внутри с флагом отмены в cleanup.

Другие вопросы раздела