Суворий режим

StrictMode – це інструмент для виявлення потенційних проблем у додатку. Так само як і Fragment, StrictMode не рендерить видимого UI. Він активує додаткові перевірки та попередження для своїх нащадків.

Примітка:

Перевірки суворого режиму виконуються лише в режимі розробки; вони не впливають на продакшн-збірку.

Ви можете увімкнути суворий режим для будь-якої частини вашого додатку. Наприклад:

import React from 'react';

function ExampleApplication() {
  return (
    <div>
      <Header />
      <React.StrictMode>
        <div>
          <ComponentOne />
          <ComponentTwo />
        </div>
      </React.StrictMode>
      <Footer />
    </div>
  );
}

У наведеному вище прикладі, перевірки суворого режиму не будуть виконуватись для компонентів Header та Footer. Проте компоненти ComponentOne та ComponentTwo, а також всі їхні нащадки матимуть перевірки.

StrictMode наразі допомагає в:

Додаткова функціональність буде додана в майбутніх релізах React.

Ідентифікація небезпечних методів життєвого циклу

В цій статті пояснюється, чому деякі застарілі методи життєвого циклу є небезбечними для використання в асинхронних React-додатках. Проте може бути важко проконтролювати використання цих методів життєвого циклу, якщо ваш додаток використовує сторонні бібліотеки. На щастя, суворий режим може допомогти в цьому випадку!

Коли увімкнено суворий режим, то React створює список всіх класових компонентів, які використовують небезпечні методи життєвого циклу, та виводить попередження з інформацією про ці компоненти, наприклад:

strict mode unsafe lifecycles warning

Вирішення проблем, знайдених суворим режимом, сьогодні спростить для вас отримання вигоди від асинхронного рендеру в майбутніх релізах React.

Попередження про використання застарілого API рядкових рефів

Раніше React надавав два способи управління рефами: застарілий API рядкових рефів та API функцій зворотнього виклику. Незважаючи на те, що API рядкових рефів був зручніший у використанні, він мав декілька недоліків і тому ми офіційно рекомендували використовувати форму функції зворотнього виклику.

React версії 16.3 вводить третій варіант, який пропонує зручність рядкових рефів але без їхніх недоліків:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    this.inputRef = React.createRef();
  }

  render() {
    return <input type="text" ref={this.inputRef} />;
  }

  componentDidMount() {
    this.inputRef.current.focus();
  }
}

Оскільки об’єкти-рефи були додані значною мірою як заміна рядкових рефів, то суворий режим тепер попереджує про використання рядкових рефів.

Примітка:

Рефи-функції зворотнього виклику продовжують підтримуватись на додачу до нового API createRef.

Вам не потрібно заміняти рефи-функції зворотнього виклику у ваших компонентах. Вони трохи більш гнучкі і тому залишаться як просунута можливість.

Дізнатись більше про новий API createRef можна тут.

Попередження про використання застарілого виклику findDOMNode

Колись React підтримував виклик findDOMNode для пошуку DOM-вузла в дереві по вказаному екзепляру класа. Зазвичай вам це не потрібно, тому що ви можете прикріпити реф безпосередньо до DOM-вузла.

findDOMNode також може бути застосований до класових компонентів, але це порушувало рівні абстракції, дозволяючи батьківському компоненту вимагати, щоб відбувся рендер певного дочірнього елементу. Це створює небезпеку рефакторингу, коли ви не можете змінити деталі реалізації компонента, тому що батьківський компонент може використовувати його DOM-вузол. findDOMNode повертає лише перший дочірній елемент, але з використанням фрагментів компонент може рендерити декілька DOM-вузлів. findDOMNode — це API одноразового читання, він повертає вам результат лише на момент, коли ви його викликаєте. Якщо дочірній компонент відрендерить інший вузол, то немає жодної можливості опрацювати цю зміну. Внаслідок цього findDOMNode працював лише якщо компоненти завжди повертали єдиний DOM-вузол, що ніколи не змінювався.

Замість цього ви можете зробити це явно, передавши реф у ваш компонент та далі в DOM з використанням перенаправлення рефів.

Ви також можете додати DOM-вузол обгортку у ваш компонент і прикріпити реф прямо до нього.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.wrapper = React.createRef();
  }
  render() {
    return <div ref={this.wrapper}>{this.props.children}</div>;
  }
}

Примітка:

Можна використати CSS-атрибут display: contents, якщо ви не хочете, щоб вузол був частиною розмітки.

Виявлення несподіваних побічних ефектів

По суті, React виконує роботу в два етапи:

  • Стадія рендеру визначає, які саме зміни потрібно зробити, наприклад в DOM. На цій стадії React викликає метод render і потім порівнює результат з попереднім рендером.
  • Стадія фіксації — це коли React застосовує будь-які зміни. У випадку React DOM — це стадія, коли React вставляє, оновлює та видаляє вузли DOM. На цій стадії React також викликає методи життєвого циклу, такі як componentDidMount та componentDidUpdate.

Стадія фіксації зазвичай дуже швидка, але рендер може бути повільним. З цієї причини майбутній асинхронний режим (який поки ще не увімкнений за замовчуванням) розбиває обсяг роботи рендеру на частини, призупиняючись і продовжуючи роботу, щоб запобігти блокуванню браузера. Це означає, що React перед фіксацією може викликати методи життєвого циклу стадії рендеру більше ніж один раз, або викликати їх та взагалі не зафіксувати зміни (через помилку або переривання вищого пріоритету).

Методи життєвого циклу стадії рендеру включають наступні методи класового компоненту:

  • constructor
  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate
  • getDerivedStateFromProps
  • shouldComponentUpdate
  • render
  • Функції-оновлювачі стану компонента, що передаються першим аргументом в setState

Оскільки наведені вище методи можуть бути викликані більше ніж один раз, то важливо, щоб вони не містили побічних ефектів. Ігнорування цього правила може привести до ряду проблем, включаючи витік пам’яті або недійсний стан додатку. На жаль, виявити ці проблеми може бути важко, оскільки вони часто бувають недетермінованими.

Суворий режим не може автоматично виявити побічні ефекти за вас, але він може допомогти їх помітити, роблячи їх більш детермінованими. Це досягається завдяки навмисному викликлу наступних методів двічі:

  • Метод constructor класового компоненту
  • Метод render
  • Функції-оновлювачі стану компонента, що передаються першим аргументом в setState
  • Статичний метод життєвого циклу getDerivedStateFromProps

Примітка:

Це застосовується лиже в режимі розробки. Методи життєвого циклу ніколи не будуть викликані двічі в продакшн-режимі.

Для прикладу, розглянемо наступний код:

class TopLevelRoute extends React.Component {
  constructor(props) {
    super(props);

    SharedApplicationState.recordEvent('ExampleComponent');
  }
}

На перший погляд він не здається проблематичним. Але якщо метод SharedApplicationState.recordEvent не ідемпотентний, то створення багатьох екземплярів цього компонента може призвести до недійсного стану додатку. Такий тип витончених помилок може не проявляти себе під час розробки або робити це непослідовно і тому може залишитися не поміченим.

Суворий режим робить подібні патерни більш помітними, навмисно двічі викликаючи методи, такі як конструктор компонента.

Виявлення застарілого контекстного API

Використання застарілого контекстного API часто призводило до помилок, тому він буде видалений в майбутній мажорній версії React. Він все ще працює в усіх релізах версії 16.x, але показуватиме це попередження у суворому режимі:

warn legacy context in strict mode

Ознайомтесь з документацією нового контекстного API для спрощення переходу на нову версію.