Життєвий цикл
Існує кілька стадій життєвого циклу – монтування, оновлення та розмонтування.
Під час кожної з них у компонента-класу викликаються методи, що наслідуються від
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;
}
}