Главная » Хабрахабр » [Перевод] Понимание жизненного цикла React-компонента

[Перевод] Понимание жизненного цикла React-компонента

React предоставляет разработчикам множество методов и «хуков», которые вызываются во время жизненного цикла компонента, они позволяют нам обновлять UI и состояние приложения. Когда необходимо использовать каждый из них, что необходимо делать и в каких методах, а от чего лучше отказаться, является ключевым моментом к пониманию как работать с React.
Update:

3 появились два дополнительных метода жизненного цикла и несколько методов объявлено устаревшими, подробности по ссылке.
(Прим. В React 16. Статью по ссылке добавил ниже) переводчика: Хотя некоторые методы и объявлены устаревшими, их описание, на мой взгляд, все равно будет полезно, хотя бы тем разработчикам, которые работают с предыдущими версиями React и в целом для понимания вместо каких методов и для чего были введены новые.

Constructor:

Очень важно вызывать функцию super в случаях, когда наш класс расширяет поведение другого класса, который имеет конструктор. Конструкторы являются основной ООП – это такая специальная функция, которая будет вызываться всякий раз, когда создается новый объект. Вот почему мы имеем доступ к this.props только после вызова super. Выполнение этой специальной функции будет вызывать конструктор нашего родительского класса и разрешать ему проинициализировать себя. Component) (имеется ввиду вызов super(props) в классе-наследнике React.

Поэтому конструкторы — это отличное место для инициализации компонента – создание любых полей (переменные начинающиеся с this.) или инициализации состояния компонента на основе полученных props.

Во всех других случаях необходимо использовать this.setState. Это также единственное место где вы можете изменять/устанавливать состояние (state) напрямую перезаписывая поле this.state.

ДЕЛАЙТЕ:

  • Устанавливайте изначальное состояние компонента
  • Если не используется class properties синтаксис – подготовьте все поля класса и вызовете bind на тех функциях, что будут переданы как коллбеки.

НЕ ДЕЛАЙТЕ:

  • Не выполняйте никаких сайд-эффектов (side effects) (Вызовы AJAX и т.д.)

[deprecated]componentWillMount

Вообще исторически были некоторые причины использовать componentWillMount поверх конструктора — смотри react-redux issue, но на данный момент практика, описанная там, устарела. componentWillMount не очень отличается от конструктора – она также вызывается лишь раз в изначальном жизненном цикле.

Но это не тот случай – хотя реквест и будет инициализирован перед render, он не успеет выполниться прежде чем render будет вызван. У многих возможно появится соблазн использовать эту функцию для отправки реквеста на получение данных и они будут ожидать, что данные будут доступны прежде чем отработает изначальный render.

Поэтому, не рекомендуется использовать эту функцию для выполнения любых операций вызывающих сайд-эффекты. Кроме того, с изменениями в React Fiber (после релиза React 16 beta) эта функция может быть вызвана несколько раз перед вызовом изначального render, что может привести к различным побочным эффектам, связанным с этим.

Поэтому если некоторый сайд-эффект нацелен на серверную часть, эта функция может быть использована как исключение. Также важно отметить, что эта функция вызывается, когда используется рендеринг на стороне сервера (server side rendering), когда ее антипод – componentDidMount не будет вызван на сервере, но будет на клиенте.

И наконец функция setState может быть свободно использована и не будет вызывать перерисовку компонента.

ДЕЛАЙТЕ:

  • Обновляйте состояние через this.setState
  • Выполняйте последние оптимизации
  • Вызывайте сайд-эффекты (Вызов AJAX и т.д.) только в случае server-side-rendering.

НЕ ДЕЛАЙТЕ:

  • Не выполняйте никаких сайд-эффектов (Вызов AJAX и т.д.) на стороне клиента.

[deprecated]componentWillReceiveProps(nextProps)

Эта функция будет вызываться при каждом апдейт жизненном цикле, который будет происходить при изменениях в props (когда перерисовывается родительский компонент) и будет принимать маппинг всех передаваемых props, не важно изменялось значение какого-либо свойства или нет с предыдущей фазы перерисовки.

вызов this.setState здесь не будет приводить к дополнительной перерисовке. Эта функция будет идеальна, если у вас есть какой-нибудь компонент, часть состояния которого (state), зависит от props передаваемых от родительского компонента, т.к.

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

Для примера:

componentWillReceiveProps(nextProps)
}

В связи с тем, что в React Fiber (после 16 beta) эта функция может вызываться несколько раз перед функцией render, не рекомендуется выполнять здесь никакие операции вызывающие сайд-эффекты.

ДЕЛАЙТЕ:

  • Синхронизируйте состояние (state) с props

НЕ ДЕЛАЙТЕ:

  • Не выполняйте никаких сайд-эффектов (Вызовы AJAX и т.д.)

shouldComponentUpdate(nextProps, nextState, nextContext)

Если перерисовка компонента довольно тяжелая (например генерация чарта, графика) или не рекомендуется по каким-либо перфоманс причинам, то у разработчиков есть доступ к специальной функции, которая будет вызываться всякий раз при апдейт цикле. По умолчанию, все компоненты будут перерисовывать себя всякий раз, когда их состояние (state) изменяется, изменяется контекст или они принимают props от родителя.

И разработчик может использовать эти параметры для того чтобы решить нужно ли делать перерисовку компонента или вернуть false и предотвратить ее. Эта функция будет вызываться с следующими значениями props, состоянием (state) и объектом. В противном случае от вас ожидают, что вы вернете true.

ДЕЛАЙТЕ:

  • Используйте для оптимизации производительности компонента

НЕ ДЕЛАЙТЕ:

  • Не выполняйте никаких сайд-эффектов (Вызовы AJAX и т.д.)
  • Не вызывайте this.setState

[deprecated]componentWillUpdate(nextProps, nextState)

Эта функция в основном используется для того чтобы сделать синхронизацию между состоянием (state) и props в случае если часть состояния компонента базируется на каких-либо props. Если мы не реализовали функцию shouldComponentUpdate или же решили, что компонент должен обновиться в этом рендер цикле, вызовется другая функция жизненного цикла.

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

Подобно всем другим componentWill* функциям, эта функция может быть вызывана несколько раз перед render, поэтому не рекомендуется выполнять здесь никакие операции вызывающие сайд-эффекты.

ДЕЛАЙТЕ:

  • Синхронизируйте состояние (state) с props

НЕ ДЕЛАЙТЕ:

  • Не выполняйте никаких сайд-эффектов (Вызовы AJAX и т.д.)

componentDidUpdate(prevProps, prevState, prevContext)

Это означает, что вы можете быть уверены, что компонент и все его дочерние компоненты уже перерисовали себя. Эта функция будет вызываться после того как отработала функция render, в каждом цикле перерисовки.

Как componentWillUpdate и componentWillRecieveProps в эту функцию передается предыдущие props, состояние (state) и контекст, даже если в этих значениях не было изменений. В связи с этим эта функция является единственной функцией, что гарантировано будет вызвана только раз в каждом цикле перерисовки, поэтому любые сайд-эффекты рекомендуется выполнять именно здесь. Поэтому разработчики должны вручную проверять переданные значения на изменения и только потом производить различные апдейт операции.

componentDidUpdate(prevProps) { if(prevProps.myProps !== this.props.myProp) { // У this.props.myProp изменилось значение // Поэтому мы можем выполнять любые операции для которых // нужны новые значения и/или выполнять сайд-эффекты // вроде AJAX вызовов с новым значением - this.props.myProp }
}

ДЕЛАЙТЕ:

  • Выполняйте сайд-эффекты (Вызовы AJAX и т.д.)

НЕ ДЕЛАЙТЕ:

  • Не вызывайте this.setState т.к. это будет вызывать циклическую перерисовку.

Исключение из правила выше это апдейт состояния, которое базируется на каких-либо DOM свойствах, которые могут вычислены только после того, как компонент перерисовался (например позиция/размеры каких-либо DOM узлов). Но будьте внимательны и предотвращайте повторное обновление если значение фактически не изменилось, т.к. это может привести к циклической перерисовке.

componentDidCatch(errorString, errorInfo)

он позволяет реагировать на события, происходящие в дочернем компоненте, а конкретно на любые неперехваченные ошибки в любом из дочерних компонентов. Дополнение в React 16 – этот метод жизненного цикла является особым, т.к.

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

componentDidCatch(errorString, errorInfo) { this.setState({ error: errorString }); ErrorLoggingTool.log(errorInfo);
}
render() { if(this.state.error) return <ShowErrorMessage error={this.state.error} /> return ( // render normal component output );
}

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

  • errorString — .toString() сообщение о ошибке
  • errorInfo – объект с одним полем componentStack, которое содержит стектрейс, где произошла ошибка.

in Thrower in div (created by App) in App

componentDidMount

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

эта функция гарантирована будет вызвана лишь раз, то это превосходный кандидат для выполнения любых сайд-эффектов, как то AJAX запросы. Т.к.

ДЕЛАЙТЕ:

  • Выполняйте сайд-эффекты (Вызовы AJAX и т.д.)

НЕ ДЕЛАЙТЕ:

  • Не вызывайте this.setState т.к. это вызовет перерисовку.

Исключение из правила выше это апдейт состояния, которое базируется на каких-либо DOM свойствах, которые могут вычислены только после того, как компонент перерисовался (например позиция/размеры каких-либо DOM узлов). Но будьте внимательны и предотвращайте повторное обновление если значение фактически не изменилось, т.к. это может привести к циклической перерисовке.

componentWillUnmount

Используйте эту функцию для «очистки» после компонента, если он использует таймеры (setTimeout, setInterval), открывает сокеты или производит любые операции, которые нуждаются в закрытии или удалении.

ДЕЛАЙТЕ:

  • Удаляйте таймеры и слушателей (listeners) созданных во время жизни компонента.

НЕ ДЕЛАЙТЕ:

  • Не вызывайте this.setState, не стартуйте новых слушателей или таймеры.

Циклы компонента

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

Создание компонента

Первый цикл это создание компонента, которое обычно происходит при первом обнаружении компонента в распарсенном JSX дереве:

Компонент перерисовывается в связи с перерисовкой родительского компонента

Компонент перерисовывается в связи с внутренними изменениями (например вызов this.setState())

Компонент перерисовывается в связи с вызовом this.forceUpdate

Компонент перерисовывается в связи с перехватом ошибки

Компонент может определять специальный слой, который может перехватывать ошибки и предоставлять новый метод жизненного цикла – componentDidCatch – который дает разработчику возможность обработать или залогировать эти ошибки. Введено в React 16 как ErrorBoundaries.

ТУТ вы можете найти и поиграться с этим симулятором. @James_k_nelson — недавно опубликовал componentWillRecieveProps симулятор.

React 16.3+ жизненный цикл компонента

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

static getDerivedStateFromProps(nextProps, prevState)

Ее основной смысл — это замена componentWillRecieveProps. Основная ответственность этой новой функции — это убедиться, что состояние (state) и props синхронизированы, когда это необходимо.

getDerivedStateFromProps – это статическая функция и поэтому не имеет доступа к this – вместо этого от вас ожидают, что вы вернете объект, который будет смержен в будущее состояние компонента (в точности как работа с setState!)

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

getSnapshotBeforeUpdate(prevProps, prevState)

Другая из двух новых функций, вызывается в так называемой “pre-commit фазе”, прямо перед изменениями из VDOM, которые должны быть отображены в DOM.

Добавлением getSnapshotBeforeUpdate вы сможете рассчитать текущее положение скролла и восстанавливать его через апдейт DOM-а. Ее можно использовать в основном, если вам нужно прочитать текущее состояние DOM.
Например у вас есть приложение, в котором новые сообщения добавляются сверху экрана – если пользователь будет скроллить вниз, и добавится новое сообщение, экран будет «прыгать» и это сделает UI тяжелее в использовании.

Возвращаемое значение будет передано в componentDidUpdate как 3-й параметр. Хотя функция не является статической, рекомендуется возвращать значение, а не апдейтить компонент.

Устаревшие функции

Следующие функции будут маркированы как устаревшие и в следующих релизах переименованы: Несмотря на то, что новые функции делают ваш переход на AsyncMode легче, вас не заставляют мигрировать весь ваш код.

  • componentWillRecieveProps – UNSAFE_componentWillRecieveProps
  • componentWillUpdate – UNSAFE_componentWillUpdate

Вы увидите варнинги в следующей major версии, и функции будут переименованы (переименованные версии будут сохранены!) в версии 17.0

Dan Abramov суммировал все изменения в одной картинке:

Спасибо за внимание!


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

[DotNetBook] Время занимательных историй: исключительно исключительные ситуации

Причем если попытаться их классифицировать, то как и было сказано в самом начале главы, есть исключения родом из самого . Существует ряд исключительных ситуаций, которые скажем так… Несколько более исключительны чем другие. Их в свою очередь можно разделить на две ...

Кастомный подход для нормализации и сброса стилей (custom-reset.css)

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