3.18 Строгий режим


StrictMode - инструмент для выделения потенциальных проблем в приложении. Как и Fragment, StrictMode не отображает какой-либо видимый UI. Он активирует дополнительные проверки и предупреждения для своих потомков.


Внимание!

Проверки строгого режима работают только в режиме разработки; они не влияют на production билд.

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


Код
    
  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 компилирует список всех компонентов-классов, использующих небезопасные методы жизненного цикла, и отображает предупреждающее сообщение с информацией об этих компонентах, например:

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




Ранее React предоставлял два способа управления ссылками ref: устаревший строковый API и API обратного вызова. Хотя строковый API был более удобным, он имел ряд недостатков, поэтому наша официальная рекомендация заключалась в том, чтобы вместо него использовать форму обратного вызова.

React 16.3 добавил третий вариант, который предлагает удобство строки ref без каких-либо недостатков:


Код
    
  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();
    }
  }
  

Поскольку ссылки на объекты по большей части были добавлены в качестве замены строковых ref, строгий режим теперь предупреждает об использовании строковых ссылок.


Внимание!

API обратного вызова для ссылок будет продолжать поддерживаться в дополнение к новому API createRef.

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

Подробнее о новом API createRef читайте здесь .




Ранее React использовал метод findDOMNode для поиска узла DOM по заданному экземпляру класса. Обычно вам это не нужно, так как вы можете прикрепить ссылку непосредственно к узлу DOM.



findDOMNode также может использоваться на компонентах-классах, но это нарушает уровни абстракции, позволяя родителю требовать отрисовки определенных потомков. Также это создает опасность во время рефакторинга, когда вы не можете изменить детали реализации компонента, потому что родитель может получать доступ к его DOM узлу. findDOMNode возвращает только первого потомка, но с использованием фрагментов компонент может отображать несколько узлов DOM. findDOMNode - это API для однократного чтения. Он дает вам ответ только тогда, когда вы его об этом попросите. Если дочерний компонент отображает другой узел, нет способа обработать это изменение. Поэтому findDOMNode работает только в том случае, если компоненты всегда возвращают один узел DOM, который никогда не изменяется.

Вместо этого можно использовать передачу ссылок.

Вы также можете добавить обёртку дла DOM-узла в свой компонент и прикрепить ссылку непосредственно к ней.


Внимание!

В CSS может использоваться атрибут display: contents, если вы не хотите, чтобы узел был частью лэйаута.


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




Концептуально, React работает в две фазы:

  • Фаза отрисовки (render) определяет, какие изменения необходимо произвести. В данной фазе React вызывает render, а затем сравнивает результат с предыдущим результатом вызова render.
  • Фаза фиксации (commit) - в ней React применяет любые изменения. (В случае React DOM - это фаза, когда React вставляет, обновляет и удаляет узлы DOM.) В данной фазе React также вызывает методы жизненного цикла, такие как componentDidMount и componentDidUpdate.

К методам жизненного цикла фазы отрисовки относятся следующие методы компонента-класса:

  • constructor
  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate
  • getDerivedStateFromProps
  • shouldComponentUpdate
  • render
  • обновляющие функции метода setState (первый аргумент)

Поскольку вышеупомянутые методы могут быть вызваны более одного раза, важно, чтобы они не содержали каких-либо сторонних эффектов. Игнорирование этого правила может привести к множеству проблем, включая утечку памяти и нерелевантное состояние приложения. К сожалению, бывает довольно трудно обнаружить эти проблемы, поскольку они часто могут быть недетерминированными.

Строгий режим не может автоматически обнаруживать для вас побочные эффекты, но он может помочь вам определить их, сделав их немного более детерминированными. Это достигается путем преднамеренного двойного вызова следующих методов:

  • Метод constructor компонента-класса.
  • Метод render.
  • обновляющие функции метода setState (первый аргумент)
  • Статический метод getDerivedStateFromProps.


Внимание!

Это применимо только к development режиму. Методы жизненного цикла не будут вызываться дважды в production режиме.

К примеру, рассмотрим следующий код:


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

      SharedApplicationState.recordEvent('ExampleComponent');
    }
  }
  

На первый взгляд данный код может не показаться проблемным. Но если метод SharedApplicationState.recordEvent не является идемпотентным, то создание экземпляра этого компонента несколько раз может привести к недопустимому состоянию приложения. Такая тонкая ошибка может не проявляться во время разработки, или же она может возникать очень непоследовательно, и поэтому может быть упущена из виду.

Умышленно производя двойные вызовы методов, таких как конструктор компонента, строгий режим делает такие проблемные шаблоны более легкими для обнаружения.




Устаревший API контекста подвержен ошибкам и будет удален в будущей major версии. Он все еще работает для всех релизов 16.x, но в строгом режиме будет показано это предупреждение:



Изучите новую документацию по API контекста в данном разделе.