Строгий режим
These docs are old and won’t be updated. Go to react.dev for the new React docs.
These new documentation pages teach modern React and include live examples:
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
помогает в:
- Обнаружении небезопасных методов жизненного цикла
- Предупреждении об использовании устаревшего API строковых реф
- Предупреждении об использовании устаревшего метода findDOMNode
- Обнаружении неожиданных побочных эффектов
- Обнаружении устаревшего API контекста
- Обеспечение переиспользованного состояния
Дополнительные проверки будут включены в будущих релизах React.
Обнаружение небезопасных методов жизненного цикла
В этой статье рассматриваются причины, почему некоторые методы жизненного цикла небезопасно использовать в асинхронных React-приложениях. Если в приложении подключены сторонние библиотеки, то отследить использование таких методов довольно тяжело. К счастью, тут может помочь строгий режим!
Когда строгий режим включён, React составляет список всех классовых компонентов, которые используют небезопасные методы жизненного цикла, и отображает информацию о них таким образом:
Если избавиться от проблем, выявленных в строгом режиме, уже сегодня, то это позволит получить все преимущества конкурентного рендеринга в будущих релизах React.
Предупреждение об использовании устаревшего API строковых реф
Ранее React предоставлял два способа управления рефами: устаревшие строковые рефы и колбэк 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
выполняет поиск только один раз. Затем метод возвращает ранее полученный результат при вызове. Если дочерний компонент рендерит другой узел, то это изменение никак не отследить. Поэтому 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
может применяться для исключения узла из макета (layout).
Обнаружение неожиданных побочных эффектов
React работает в два этапа:
- Этап рендеринга (render phase) определяет, какие изменения необходимо произвести, например, в DOM. В течение этого этапа React вызывает
render
, а затем сравнивает полученный результат с результатом предыдущего рендера. - Этап фиксации (commit phase) — в нём React применяет любые изменения. В случае React DOM — это этап, когда React вставляет, обновляет и удаляет DOM-узлы. В течение этого этапа React вызывает методы жизненного цикла
componentDidMount
иcomponentDidUpdate
.
Этап фиксации обычно не занимает много времени, что нельзя сказать про этап рендеринга. По этой причине, готовящийся конкурентный режим (который по умолчанию ещё не включён) делит работу на части, периодически останавливает и возобновляет работу, чтобы избежать блокировки браузера. Это означает, что на этапе рендеринга React может вызвать методы жизненного цикла более чем один раз перед фиксацией, либо вызвать их без фиксации (из-за возникновения ошибки или прерывания с большим приоритетом).
Этап рендеринга включает в себя следующие методы жизненного цикла:
constructor
componentWillMount
(илиUNSAFE_componentWillMount
)componentWillReceiveProps
(илиUNSAFE_componentWillReceiveProps
)componentWillUpdate
(илиUNSAFE_componentWillUpdate
)getDerivedStateFromProps
shouldComponentUpdate
render
- Функции обновления
setState
(первый аргумент)
Поскольку вышеупомянутые методы могут быть вызваны более одного раза, важно, чтобы они не приводили к каким-либо побочным эффектам. Игнорирование этого правила может привести к множеству проблем, включая утечки памяти и недопустимое состояние приложения. К сожалению, такие проблемы тяжело обнаружить из-за их недетерминированности.
Строгий режим не способен автоматически обнаруживать побочные эффекты, но помогает их отследить, сделав более детерминированными. Такое поведение достигается путём двойного вызова следующих методов:
- Методы
constructor
,render
, иshouldComponentUpdate
классового компонента - Статический метод классового компонента
getDerivedStateFromProps
- Тело функционального компонента
- Функции обновления (первый аргумент
setState
) - Функции, переданные в
useState
,useMemo
, илиuseReducer
Примечание:
Это применимо только в режиме разработки. Методы жизненного цикла не вызываются дважды в продакшен-режиме.
Рассмотрим следующий пример:
class TopLevelRoute extends React.Component {
constructor(props) {
super(props);
SharedApplicationState.recordEvent('ExampleComponent');
}
}
На первый взгляд данный пример не кажется проблемным. Но если метод SharedApplicationState.recordEvent
не является идемпотентным, тогда создание этого компонента несколько раз может привести к недопустимому состоянию приложения. Такие труднонаходимые ошибки могут никак не проявить себя во время разработки или быть настолько редкими, что останутся незамеченными.
Двойной вызов таких методов, как конструктор компонента, позволяет строгому режиму легко обнаружить подобные проблемы.
Примечание:
Начиная с 17 версии, React автоматически модифицирует методы для работы с консолью (например,
console.log()
), чтобы предотвратить запись в консоль при втором вызове функций жизненного цикла. Однако в некоторых ситуациях это может привести к нежелательному поведению, в таких случаях можно воспользоваться обходным решением.Starting from React 18, React does not suppress any logs. However, if you have React DevTools installed, the logs from the second call will appear slightly dimmed. React DevTools also offers a setting (off by default) to suppress them completely.
Обнаружение устаревшего API контекста
Использование устаревшего API контекста очень часто приводило к ошибкам и поэтому он будет удалён в будущей мажорной версии. Пока что этот API доступен во всех релизах 16.x, но в строгом режиме будет выведено следующее предупреждение:
Ознакомьтесь с документацией нового API контекста, чтобы упростить переход на новую версию.
Обеспечение переиспользованного состояния
В будущем мы хотели бы добавить функцию, которая позволяет React добавлять и удалять разделы пользовательского интерфейса с сохранением состояния. Например, когда пользователь переходит от экрана к экрану и обратно, React должен иметь возможность немедленно отображать предыдущий экран. Для этого React поддерживает повторное монтирование деревьев с использованием того же состояния компонента, которое использовалось до размонтирования.
Эта функция позволит React повысить производительность «из коробки» (изначально готовому к использованию), но требует, чтобы компоненты были устойчивы к многократному монтированию и уничтожению эффектов. Большинство эффектов будут работать без каких-либо изменений, но некоторые эффекты неправильно очищают подписки в функции обратного вызова или подразумевают, что они монтируются или уничтожаются только один раз.
Чтобы помочь устранить эти проблемы, React 18 представляет новую проверку только в режиме разработки в строгом режиме. Эта новая проверка автоматически размонтирует и перемонтирует каждый компонент всякий раз, когда компонент монтируется в первый раз, восстанавливая предыдущее состояние при втором монтировании.
Чтобы продемонстрировать поведение разработки, которое вы увидите в строгом режиме с помощью этой функции, рассмотрим, что происходит, когда React монтирует новый компонент. Без строго режима, когда компонент монтируется, React создает эффекты:
* React монтирует компонент.
* Создаются эффекты макета.
* Создаются эффекты.
В строгом режиме, начинающегося с React 18, всякий раз, когда компонент монтируется в процессе разработки, React будет имитировать немедленное размонтирование и повторное монтирование компонента:
* React монтирует компонент.
* Создаются эффекты макета.
* Создаются эффекты.
* React имитирует разрушение эффектов на смонтированном компоненте.
* Эффекты макета уничтожаются.
* Эффекты уничтожаются.
* React имитирует пересоздание эффектов на смонтированном компоненте.
* Создаются эффекты макета.
* Установка эффектов.
При втором монтировании React восстановит состояние с первого монтирования. Эта функция имитирует поведение пользователя, например, переход пользователя с экрана на вкладку и обратно, гарантируя, что код будет правильно обрабатывать восстановление состояния.
Когда компонент размонтируется, эффекты уничтожаются в обычном режиме:
* React размонтирует компонент.
* Уничтожаются эффекты макета.
* Уничтожаются эффекты эффектов.
Размонтирование и повторное монтирование включает в себя:
componentDidMount
componentWillUnmount
useEffect
useLayoutEffect
useInsertionEffect
Примечание:
Это относится только к режиму разработки, для продакшена поведение остаётся неизменным.
Для получения помощи в решении распространённых проблем см.: