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

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

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

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

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

Жизненный цикл компонента

При правильном использовании React, большая часть компонентов состоит из метода render и обработчиков событий:

class ArticleItem extends React.Component {
  handleClick = (e) => {
    e.preventDefault();
    const { onClick } = this.props;
    onClick();
  }
  render() {
    const { name, description, link } = this.props;
    return (
      <div>
        <a href="{link}" onClick={this.handleClick}>{name}</a><br />
        <div>{description}</div>
      </div>
    );
  }
}

Но не все задачи решаются так просто. Представьте себе компонент <Clock />, имитирующий цифровые часы в формате чч:мм:сс. Создадим каркас:

class Clock extends React.Component {
  render() {
    const currentTime = new Date();
    return (
      <div>{currentTime.toLocaleTimeString()}</div>
    );
  }
}

Этот компонент отображает текущее время. Теперь подумаем как его обновлять. Часы, в отличие от обычных компонентов, не ожидают действий от пользователя. Они обновляются каждую секунду самостоятельно. Возникает цепочка: возникает событие => меняется текущее время => React вызывает render и меняет DOM. Начнём с состояния, добавим туда текущее время:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { date: new Date() };
  }
  render() {
    const { date } = this.state;
    return (
      <div>{date.toLocaleTimeString()}</div>
    );
  }
}

Компонент по прежнему показывает лишь текущее время, но теперь он готов к изменению. Время относится к периодическим событиям, для которых используются таймеры. Для <Clock /> подойдёт setInterval. Мы должны установить таймер сразу после отрисовки часов и очистить таймер при удалении компонента из дерева элементов.

setInterval(() => this.setState({ date: new Date() }), 1000);

Где запускать таймер? render вызывается на каждое изменение состояния, а значит он не подходит. Ведь тогда <Clock /> будет запускать новый таймер каждую секунду. Конструктор, кажется, более подходящим местом, но здесь нас ожидает сюрприз. Вызов конструктора и отрисовка часов в DOM дереве, в общем случае, два независимых события. Посмотрите на код:

// Вызывается конструктор
const clock = <Clock />;

// Что-то долго делаем ещё

// Отрисовываем
reactDOM.render(
  clock,
  document.getElementById('root')
);

Эти часы ещё не находятся в DOM-дереве, но уже во всю работают и обновляются. Стоит ли об этом беспокоиться? Да, такое поведение крайне неожиданно, оно мешает тестированию и расходует процессорное время. Кроме того, конструктор никак не помогает с удалением таймера.

Каждый компонент React проходит несколько стадий в процессе своей жизни: он создаётся, затем добавляется в DOM, получает пропсы, и, наконец, удаляется из дерева. Этот процесс называют жизненным циклом компонента (Component Lifecycle). React предоставляет набор методов, которые позволяют встроиться в этот процесс. Например, запуск часов логичнее всего сделать сразу после их отрисовки. В этом нам поможет метод componentDidMount. Он вызывается сразу после отрисовки компонента. Происходит это ровно один раз.

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { date: new Date() };
  }

  componentDidMount() {
    // Сохраняем идентификатор таймера
    this.timerId = setInterval(() => this.setState({ date: new Date() }), 1000);
  }

  render() {
    const { date } = this.state;
    return (
      <div>{date.toLocaleTimeString()}</div>
    );
  }
}

Обратите внимание на то, как мы сохраняем таймер внутри объекта. Он не участвует в представлении, поэтому нет необходимости использовать состояние.

Теперь выполним очистку таймера. Для этого подойдёт метод componentWillUnmount, который выполняется прямо перед удалением компонента из DOM.

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { date: new Date() };
  }

  componentDidMount() {
    this.timerId = setInterval(() => this.setState({ date: new Date() }), 1000);
  }

  componentWillUnmount() {
    clearInterval(this.timerId);
  }

  render() {
    const { date } = this.state;
    return (
      <div>{date.toLocaleTimeString()}</div>
    );
  }
}

Часы приобрели законченный вид.

Мы рассмотрели два метода, позволяющих встраиваться в жизненный цикл компонента, но их значительно больше. Они делятся на три независимые группы:

Монтирование (Mounting)

Эти методы вызываются во время создания объекта и вставки его в DOM.

  • constructor()
  • static getDerivedStateFromProps()
  • render()
  • componentDidMount()

Обновление (Updating)

Обновление может происходить при изменении свойств или состояния. Эти методы вызываются во время перерисовки.

  • static getDerivedStateFromProps()
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate()
  • componentDidUpdate()

Удаление или демонтирование (Unmount)

В эту группу входит один метод. Он вызывается во время удаления компонента из DOM.

  • componentWillUnmount()

Такое количество методов объясняется сложностью реальной разработки. Но, на практике, лишь некоторые используются регулярно. К таким методам относится componentDidMount. С его помощью устанавливают таймеры, выполняют AJAX-запросы, меняется DOM в обход React. Последнее бывает нужно при интеграции со сторонними библиотеками.


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

  1. Методы жизненного цикла

<span class="translation_missing" title="translation missing: ru.web.courses.lessons.mentors.mentor_avatars">Mentor Avatars</span>

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

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

Для полного доступа к курсу нужна профессиональная подписка

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

Получить доступ
115
курсов
892
упражнения
2241
час теории
3196
тестов

Зарегистрироваться

или войти в аккаунт

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

  • 115 курсов, 2000+ часов теории
  • 800 практических заданий в браузере
  • 250 000 студентов

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

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

Логотип компании Альфа Банк
Логотип компании Rambler
Логотип компании Bookmate
Логотип компании Botmother

Есть вопрос или хотите участвовать в обсуждении?

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

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