Russian (Pусский) translation by Marat Amerov (you can also view the original English article)
Обзор
Компоненты React инкапсулируют части пользовательского интерфейса. Ваш полный пользовательский интерфейс приложения React отображается как дерево из множества вложенных компонентов. В зависимости от потока приложения отдельные компоненты должны выполнять некоторые задачи до и после рендеринга, а также до и после обновления.
Наконец, важна очистка и обработка ошибок. React предоставляет множество методов жизненного цикла, которые вы можете переопределить и добавить свою собственную логику в нужное место. В этом уроке вы узнаете о жизненном цикле компонента React от колыбели до могилы, какие методы доступны на каждом этапе и когда это целесообразно переопределить.
Обратите внимание, что в этом уроке я использую современный стиль классов ES6.
Компонент PopularBar
Я буду использовать компонент под названием PopularBar, чтобы проиллюстрировать все методы жизненного цикла и как они себя ведут. Полный исходный код доступен на GitLab.
В PopularBar есть два других компонента, называемых ClickCounter
. Каждый компонент ClickCounter
содержит кнопку с emoji и отображает количество кликов, добавленных в свойство count, которое он получает от своего хоста. Вот метод render()
компонента ClickCounter
:
render() { return ( <span className='padded' onClick={() => { let clickCount = this.state.clickCount + 1 this.setState({clickCount: clickCount}) }} > <button>{this.props.emoji}</button> {this.getTotal() < 100 ? this.getTotal() : "99+"} </span> ); }
Компонент PopularBar отображает два компонента ClickCounter с большими пальцами вверх и вниз в виде emojis. Обратите внимание, что если prop "show" является ложью, то он отображает пустой div. Это будет важно позже, когда мы обсудим монтирование и размонтирование.
render() { if (!this.props.show) { return (<div />) } return ( <div className="padded" style={this.props.style}> <ClickCounter emoji={thumbsup} count={this.props.upCount} /> <ClickCounter emoji={thumbsdown} count={this.props.downCount} /> </div> ) }



Монтирование
Компоненты React существуют, когда они отображаются родительским компонентом или корневым приложением. Но прежде чем компонент может быть отображен, его нужно сконструировать (только один раз) и установить в виртуальный DOM (каждый раз он добавляется в виртуальный DOM).
Порядок событий заключается в том, что сначала компонент сконструирован, затем вызывается метод componentWillMount()
, компонент монтируется в виртуальный DOM, а затем вызывается componentDidMount()
. Это дает вам множество возможностей для выполнения различных типов инициализации.
Конструктор
Конструктор для компонента будет вызываться один раз для каждого приложения (если вы обновите страницу в своем браузере, то это считается новым приложением). Вот конструктор компонента PopularBar. Он не делает ничего, кроме вызова super()
, который обязателен, и логирования в консоль.
class PopularBar extends Component { constructor() { super() console.log('--- PopularBar constructor is here!') }
Конструктор ClickCounter инициализирует стейт clickCount
равным нулю:
class ClickCounter extends Component { constructor(props) { super(props) this.state = { clickCount: 0 } console.log(props.emoji + '=== ClickCounter constructor is here!') }
Это прекрасный пример инициализации, которая должна выполняться один раз для каждого приложения. Если компонент ClickCounter монтируется несколько раз, он должен сохранять кол-во кликов.
ComponentWillMount
Метод componentWillMount()
вызывается перед монтированием компонента, поэтому компонента еще нет. В общем, на этом этапе не так уж многое можно сделать, если у вас нет специальной инициализации, которая происходит каждый раз, когда компонент монтируется, но даже это может подождать до метода componentDidMount()
.
Вот реализация методов для PopularBar и ClickCounter:
// PopularBar componentWillMount() { console.log('--- PopularBar will mount. Yay!') } // ClickCounter componentWillMount() { console.log(this.props.emoji + '=== ClickCounter will mount. Yay!') }
Вы можете вызвать this.setState()
здесь, если хотите. Очевидно, что props недоступен.
ComponentDidMount
Здесь компонент уже смонтирован, и вы можете выполнять любую работу, требующую доступа к компоненту в контексте виртуального DOM. Вот реализация методов для PopularBar и ClickCounter. Компонент уже существует, поэтому его свойства (props) могут быть доступны и отображены.
componentDidMount() { console.log('--- PopularBar did mount. upCount: ' + this.props.upCount + ', downCount: ' + this.props.downCount) } // ClickCounter componentDidMount() { console.log(this.props.emoji + '=== ClickCounter did mount. count: ' + this.props.count) }
Чтобы подвести итог с монтированием, давайте посмотрим порядок событий в PopularBar и двух компонентах ClickCounter, которые он содержит. Для вашего удобства я показываю emoji для каждого ClickCounter, поэтому их можно отличить.
--- PopularBar constructor is here! --- PopularBar will mount. Yay! 👍=== ClickCounter constructor is here! 👍=== ClickCounter will mount. Yay! 👎=== ClickCounter constructor is here! 👎=== ClickCounter will mount. Yay! 👍=== ClickCounter did mount. count: 5 👎=== ClickCounter did mount. count: 8 --- PopularBar did mount. upCount: 5, downCount: 8componentWillMount(). Затем вызываются методы constructor иcomponentWillMount()
для каждого компонента ClickCounter, за которым следуют вызовыcomponentDidMount()
для обоих компонентов ClickCounter. Наконец, вызывается методcomponentDidMount()
компонента PopularBar. В целом, поток вложенный, где все подкомпоненты должны быть полностью смонтированы до того, как их содержащий компонент будет полностью смонтирован.unted.componentWillReceiveProps() вызывается при получении новых props из контейнера. У вас есть доступ к текущим props черезthis.props
и к следующим props через параметрnextProps
. Вот методcomponentWillReceiveProps()
компонента ClickCounter.unter.componentWillReceiveProps(nextProps) { console.log(this.props.emoji + '=== ClickCounter will receive props. ' + 'next props: ' + nextProps.count) } this.setState() здесь. here.shouldComponentUpdate() является ключевым. Он вызывается, когда принимаются новые props (после вызоваcomponentWillReceiveProps()
) или после изменения состояния компонента в другом месте. Если вы не реализуете этот метод, компонент будет рендерится каждый раз. time.
shouldComponentUpdate().code>.shouldComponentUpdate(nextProps, nextState) { let currTotal = this.getTotal() let shouldUpdate = currTotal < 100 console.log(this.props.emoji + '=== ClickCounter should ' + (shouldUpdate ? '' : 'NOT ') + 'update') return shouldUpdate }componentWillUpdateMethod() вызывается после компонентаshouldComponentUpdate()
, только еслиshouldComponentUpdate()
возвратил true. На этом этапе у вас есть как следующие props, так и следующий стейт. Вы не можете изменить стейт здесь, потому что это вызовет повторениеshouldComponentUpdate()
.again.componentWillUpdate(nextProps, nextState) { console.log(this.props.emoji + '=== ClickCounter will update' + ' nextProps.count: ' + nextProps.count + ' nextState.clickCount: ' + nextState.clickCount) }componentDidUpdate(). Это нормально, чтобы вызватьthis.setState()
здесь, потому что рендеринг для предыдущего изменения состояния уже завершен.ready.componentDidUpdate() { console.log(this.props.emoji + '=== ClickCounter did update') }--- PopularBar constructor is here! PopularBar.js:10 --- PopularBar will mount. Yay! PopularBar.js:14 👍=== ClickCounter constructor is here! 👍=== ClickCounter will mount. Yay! 👎=== ClickCounter constructor is here! 👎=== ClickCounter will mount. Yay! 👍=== ClickCounter did mount. count: 5 ClickCounter.js:20 👎=== ClickCounter did mount. count: 8 ClickCounter.js:20 --- PopularBar did mount. upCount: 5, downCount: 8 👍=== ClickCounter should update 👍=== ClickCounter will update nextProps.count: 5 nextState.clickCount: 1 👍=== ClickCounter did updОбратите внимание, чтоnextState.clickCount
равен 1, что вызывает цикл обновления. Следующее обновление будет вызвано тем, что родительский элемент передал новые props. Чтобы облегчить это, я добавлю небольшую функцию, которая запускается каждые 5 секунд и увеличивает счет на 20. Код в основном компоненте приложения, который содержит PopularBar. Это изменение будет распространяться вплоть до ClickCounter.e ClickCounter.class App extends Component { constructor() { super() this.state = { showPopularBar: true, upCount: 5, downCount: 8 } } componentDidMount() { this.timer = setInterval(this.everyFiveSeconds.bind(this), 5000); } everyFiveSeconds() { let state = this.state state.upCount += 20 this.setState(state) Вот результат. Обратите внимание, что вызван метод ClickCounterwillReceiveProps()
, аnextState.clickCount
остается равным нулю, аnextProps.Count
теперь 25.ode> is now 25.--- PopularBar constructor is here! --- PopularBar will mount. Yay! 👍=== ClickCounter constructor is here! 👍=== ClickCounter will mount. Yay! 👎=== ClickCounter constructor is here! 👎=== ClickCounter will mount. Yay! 👍=== ClickCounter did mount. count: 5 👎=== ClickCounter did mount. count: 8 --- PopularBar did mount. upCount: 5, downCount: 8 👍=== ClickCounter will receive props. next props:25 👍=== ClickCounter should update 👍=== ClickCounter will update nextProps.count: 25 nextState.clРазмонтирование и обработка ошибокnting andКомпоненты могут быть размонтированы и смонтированы снова, и могут быть ошибки во время жизненного цикла компонента.ifecycle Component Will Unmount3>ComponeЕсли компонент не отображается его контейнером, он размонтируется из виртуальной DOM и вызывается метод componentWillUnmount() размонтированного компонента. PopularBar не будет отображать подкомпоненты ClickCounter, если prop show является false. Компонент приложения отображает PopularBar и передает props show на основе флажка.p based Вот методrender()
приложения:>render() method:render() { return ( <div> <h1>Popular Bar</h1> <label> <input type='checkbox' defaultChecked={this.state.showPopularBar} ref='showPopularBar' onChange={() => this.setState( {showPopularBar: !this.state.showPopularBar}) } /> Show popular bar </label> <PopularBar show={this.state.showPopularBar} upCount={this.state.upCount} downCount={this.state.downCount} /> </div>Когда пользователь отменяет выбор флажка, PopularBar все еще отображается, но он не отображает дочерние компоненты, которые размонтируются. Вот код и вывод:the code and the output:componentWillUnmount() { console.log(this.props.emoji + '=== ClickCounter will unmount :-(') } Output: 👍=== ClickCounter will unmount :-( 👎=== ClickCounter wiМетодcomponentDidUnmount()
отсутствует, поскольку на данный момент нет компонента.o componeComponentDidCatchВ React 16 был добавлен метод
ComponentDidCatch()
. Он разработан, чтобы помочь с ошибками во время рендеринга, которые ранее приводили к неясным сообщениям об ошибках. Теперь можно определить специальные граничные компоненты для обработки ошибок, которые обертывают любой дочерний компонент, который может вызывать ошибки, а граничный компонент ошибки будет отображаться только в случае возникновения ошибки.nly if thЗаключениеcurred.render(), но желательно знать, что в более специализированных обстоятельствах вам не придется смотреть на черный ящик.ft stariЗа последние пару лет React приобрел большую популярность. Фактически, у нас есть ряд элементов на рынке, доступных для покупки, просмотра, реализации и т. д. Если вы ищете дополнительные ресурсы вокруг React, не стесняйтесь их попробовать.epage">check them out.