webroad.online
  1. 1Веб
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Инструменты
  8. 8React
  9. 9Стейт-менеджмент
  10. 10Next.js
  11. 11Формы
  12. 12Данные и бэкенд
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Анимации
  16. 16Тестирование
  17. 17Архитектура
React · Урок 3 из 7

Эффекты и useRef

Когда нужен useEffect, cleanup и когда он НЕ нужен.

Обновлено

Что такое эффект

Компонент должен быть чистым — он только вычисляет JSX. Но иногда нужно синхронизировать компонент с чем-то вне React: таймером, WebSocket-соединением, API браузера, не-React-библиотекой. Для этого есть useEffect: код, который выполняется после того, как React обновил экран.

useEffect(() => {
  const id = setInterval(tick, 1000)       // запускаете синхронизацию
  return () => clearInterval(id)           // cleanup: останавливаете её
}, [])                                     // зависимости

Жизненный цикл эффекта

  1. Компонент рендерится и появляется на экране.
  2. Эффект выполняется.
  3. Когда меняются зависимости: React выполняет старый cleanup, затем эффект заново.
  4. При размонтировании выполняется cleanup.

Зависимости

Второй аргумент Эффект выполняется
нет после каждого рендера
[] один раз, после монтирования
[a, b] после монтирования и когда меняются a или b (сравнение через Object.is)

В список кладут всё, что эффект использует из props и состояния. Помогает правило ESLint react-hooks/exhaustive-deps.

Возможно, эффект вам не нужен

Самая частая ошибка в React — эффекты для того, что не является синхронизацией с внешним миром.

Вместо эффекта, чтобы... Делайте так
вычислить данные из состояния / props вычисляйте прямо при рендере
отреагировать на клик / отправку логику — в обработчик события
сбросить состояние при смене prop key={id} на компоненте
получить данные с сервера Server Component или TanStack Query
сообщить родителю, что что-то изменилось вызовите колбэк в обработчике, который сделал изменение

Ключевой вопрос: «Этот код выполняется, потому что компонент появился на экране или потому что пользователь что-то сделал?» Первое → эффект. Второе → обработчик события.

Fetch в эффекте — если без этого никак

useEffect(() => {
  const controller = new AbortController()
  fetch(`/api/users/${id}`, { signal: controller.signal })
    .then(r => r.json())
    .then(setUser)
    .catch(() => {})
  return () => controller.abort()      // отменяет старый запрос, если id быстро меняется
}, [id])

Без cleanup получите состояние гонки: старый ответ может прийти после нового и перезаписать его.

useRef — память без перерисовки

useState useRef
Изменение вызывает рендер да нет
Чтение во время рендера да нет (только в эффектах / обработчиках)
Для того, что видно на экране ссылок на DOM, id таймеров, значений «за кулисами»
const inputRef = useRef<HTMLInputElement>(null)
<input ref={inputRef} />
inputRef.current?.focus()

Strict Mode

В режиме разработки React монтирует → размонтирует → снова монтирует каждый компонент, чтобы проверить, что у эффектов правильный cleanup. Если что-то «выполняется дважды» и ломается, у эффекта нет cleanup. В продакшене он выполняется один раз.

Коротко

  • Эффект = синхронизация с чем-то вне React; cleanup обязателен, если вы что-то запускаете.
  • Зависимости = всё, что использует эффект.
  • Вычисления → при рендере; реакции на действия → обработчики; данные → Server Components / TanStack Query.

Официальные источники

Упражнения

Была ли страница полезной?

Один клик — без регистрации.