Перейти до основного вмісту

Життєвий цикл

Існує кілька стадій життєвого циклу – монтування, оновлення та розмонтування. Під час кожної з них у компонента-класу викликаються методи, що наслідуються від React.Component. Ми можемо перевизначити їхню поведінку, додавши необхідний функціонал в рамках встановлених правил.

Всього є сім методів життєвого циклу, якщо не рахувати render і constructor. На практиці, в більшості повсякденних завдань використовують три: componentDidMount, componentDidUpdate і componentWillUnmount.

Посилання на оригінальну сторінку діаграми

Стадія монтування

Наступні методи викликаються у такому порядку, коли створюється екземпляр компонента і додається в DOM.

constructor() {}

Викликається в момент створення екземпляра компонента, перш ніж компонент буде розміщений у DOM.

  • Ініціалізує початковий стан компонента
  • Прив'язує контекст в методах
  • Не можна викликати setState()
  • У більшості випадків явне зазначення конструктора – зайве
static getDerivedStateFromProps(nextProps, prevState) {}
  • На практиці цей метод використовується вкрай рідко
  • Викликається перед render() під час монтування та перед усіма наступними викликами render, тобто після оновлення state або props
  • Можна використовувати для того, щоб встановити state, залежно від props під час кожної їх зміни
  • Повинен повернути об'єкт, яким буде оновлений стан, або null, якщо нічого оновлювати не потрібно
  • Немає доступу до this
render() {}
  • Дозволяє декларативно описати інтерфейс
  • Повертає результат JSX-виразів, піддерево Virtual DOM
  • Не можна викликати setState()
componentDidMount() {}
  • Викликається відразу після монтування компонента в DOM
  • Робимо HTTP-запити, вішаємо кастомні слухачі подій та виконуємо операції з DOM деревом
  • Виклик setState() у цьому методі викличе повторний рендер – це нормально

Стадія оновлення

Оновлення може бути викликано зміною state самого компонента або props, що йому передаються. Під час оновлення необхідно перерендерити компонент, що призводить до виклику наступних методів.

shouldComponentUpdate(nextProps, nextState) {}
  • Не викликається під час ініціалізації компонента
  • Викликається перед ререндером вже змонтованого компонента
  • Необхідний виключно для оптимізації процесу рендеру
  • За замовчуванням render відбувається щоразу з новими props або state
  • Дозволяє порівняти поточні та попередні state і props, повернувши true або false, вказуючи React, чи є необхідність оновлювати компонент
  • Якщо поверне false, то не станеться render() і componentDidUpdate()
  • Не можна викликати setState()
  • Використовувати необхідно дуже обережно, тільки після вимірів продуктивності, інакше може призвести до зворотного ефекту.
  • Можливо, варто замінити на React.PureComponent, який робитиме поверхове порівняння props. Але лише після вимірів продуктивності
getSnapshotBeforeUpdate(prevProps, prevState) {}
  • На практиці цей метод використовується дуже рідко
  • Викликається перед тим, як усі зміни готові до додавання в DOM
  • Можна використовувати для отримання DOM-значень перед оновленням, наприклад, поточну позицію скрола або розмір елемента до оновлення
  • Те, що поверне цей метод, буде передане як третій параметр snapshot в componentDidUpdate()
componentDidUpdate(prevProps, prevState, snapshot) {}
  • Викликається відразу після оновлення компонента в DOM
  • Не викликається при початковому рендері компонента
  • Можна викликати setState(), обов'язково обгорнувши його в умову перевірки зміни попередніх і наступних props або state, щоб не виник нескінченний цикл ререндера (вкладка зависне або впаде).
  • Можна робити HTTP-запити
  • Якщо в компоненті є getSnapshotBeforeUpdate(), то значення, що повертається їм, буде передане третім аргументом snapshot, в іншому випадку його значенням буде undefined

Стадія розмонтування

У якийсь момент компонент буде видалений з DOM. При цьому викликається наступний метод.

componentWillUnmount() {}
  • Викликається перед розмонтуванням та видаленням елемента з DOM
  • Добре підходить для прибирання за собою: слухачі, таймери, HTTP-запити. В іншому випадку будуть витоки пам'яті
  • Викликати setState() немає сенсу, компонент ніколи не перерендериться

Обробка помилок рендеру

React дуже любить класти весь застосунок за будь-якої помилки. Метод componentDidCatch спрацьовує у разі помилки у дочірньому компоненті та дозволяє батьківським компонентам відловлювати помилки у дітей, відображаючи запасний інтерфейс. В результаті, у разі помилки, інтерфейс не падає.

componentDidCatch(error, info) {}
  • Використовується для контролю помилок
  • Ловить помилки лише у дітей, але не в самому батьку
  • error – результат toString() об'єкта помилки
  • info – об'єкт, що описує stack trace
class ErrorBoundary extends React.Component {
state = { hasError: false };

componentDidCatch(error, info) {
// Якщо метод був викликаний, отже, є помилка!
// Встановлюємо стан
this.setState({ hasError: true });
// Також можна надіслати звіт про помилку вашому аналітичному сервісу
// logErrorToMyService(error, info);
}

render() {
// Якщо є помилка...
if (this.state.hasError) {
// Рендеримо fallback UI
return <h1>Something went wrong, please try again later :(</h1>;
}

// Якщо все ок, рендеримо дітей
return this.props.children;
}
}