Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Хук useEffect JS: React Hooks

Для выполнения побочных эффектов, например, прямой работы с DOM в React используется встроенный хук useEffect(). Он заменяет собой три колбека жизненного цикла:

  • componentDidMount()
  • componentDidUpdate()
  • componentWillUnmount()

Если вы забыли или не знали как они работают, то подробнее об этом можно прочитать в официальной документации.

Начнем с простого примера:

import React, { useState, useEffect } from 'react';

const Example = () => {
  const [count, setCount] = useState(0);

  // Работает как componentDidMount и componentDidUpdate вместе взятые
  // Запускается после рендера компонента
  // Вызывается после каждого клика по кнопке
  useEffect(() => {
    // Состояние доступно внутри за счет обычной области видимости
    alert(`Кликов ${count}`);
  });

  // На классах мы бы сделали так
  // Обратите внимание на дублирование
  // componentDidMount() {
  //   alert(`Кликов: ${count}`);
  // }
  // componentDidUpdate() {
  //   alert(`Кликов: ${count}`);
  // }

  return (
    <div>
      <p>Вы нажали {count} раз(а)</p>
      <button onClick={() => setCount(count + 1)}>
        Нажми меня
      </button>
    </div>
  );
};

Ниже пример, в котором меняется фон при каждом клике.

See the Pen js_react_hooks_use_ref by Hexlet (@hexlet) on CodePen.

Колбек, переданный в useEffect(), отрабатывает после первой отрисовки и каждого обновления компонента. То есть произошло объединение методов componentDidUpdate() и componentDidMount(). Такое изменение было сделано ради удобства. Мировая практика использования React показала, что, в основном, эффекты происходят после каждого рендера, независимо от того, первая эта отрисовка или все последующие. Как бонус, сократилось количество дублирования и кода. Какие типичные сайд-эффекты встречаются во фронтенде? Например:

  • Извлечение данных
  • Работа с BOM(Browser Object Model) API, например, Local Storage
  • Прямое изменение DOM, сюда же относятся библиотеки не совместимые с React

Действие хука useEffect() иногда можно пропускать. Такое бывает полезно либо в целях оптимизации, либо, если эффект имеет смысл только при определенных условиях. Для этого в хук вторым аргументом передается массив значений, которые надо отслеживать между отрисовками. Если хотя бы одно значение из этого массива поменялось, то колбек вызывается, если все значения остались прежними – пропускается.

useEffect(() => {
  alert(`Кликов ${count}`);
}, [count]);

// Равносильно
componentDidUpdate(prevProps, prevState) {
  if (prevState.count !== this.state.count) {
    alert(`Кликов ${count}`);
  }
}

То есть колбек будет вызван только тогда, когда изменится count. Таким же способом можно передать любой набор переменных, который мы бы хотели связать с изменением эффекта. Если хотя бы одна переменная в переданном массиве поменялась, то эффект сработает, иначе React его пропускает.

Что делать, если нужно запустить useEffect() только на момент первого рендера (сразу после монтирования)? Для этого достаточно передать пустой массив:

// Заменяет собой componentDidMount

useEffect(() => {
  alert(`Кликов ${count}`);
}, []);

Решение не самое очевидное, но технически оно не является особым случаем. К нему нужно просто привыкнуть.

Сброс эффекта

В некоторых случаях эффект нужно сбрасывать. Например, когда эффект после изменения пропсов перестает быть актуальным, его нужно "зачистить". Для этого достаточно вернуть функцию из useEffect(), внутри которой выполняется очистка:

// Предположим, что этот эффект зависит от пропса userId
useEffect(() => {
  const id = setTimeout(/* какой-то код с userId */);

  return () => clearTimeout(id);
}, [userId]);

Изменение userId приведет к сбросу текущего таймера и установке нового. Подобный код в классах потребовал бы использования аж 4 колбеков жизненного цикла.

Для имитации componentWillUnmount() достаточно соединить очистку с пустым массивом вторым параметром:

useEffect(() => {
  return () => {
    // Эта логика выполнится только при размонтировании компонента
  };
}, []);

Дополнительные материалы

  1. Использование хука useEffect
  2. Почему эффекты выполняются при каждом обновлении

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 130 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
Разработка фронтенд-компонентов веб-приложений
25 мая 10 месяцев

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»