В Интернете есть много статей о жизненном цикле реакции, и я прочитал многие из них, но я чувствую, что большинство из них просто копирует чужие статьи без собственного уникального мнения, поэтому я решил написать еще одну, основанную на на моем реальном боевом опыте и личном понимании.Эта статья о жизненном цикле React.Поскольку React был обновлен до версии 16.4, он фокусируется на жизненном цикле изменений React v16.4.Предыдущие функции жизненного цикла будут пропущены.
Давайте в общих чертах посмотрим на диаграмму жизненного цикла React16.
В React16 отказались от трех функций жизненного цикла
componentWillMountcomponentWillReceivePropscomponentWillUpdate
Примечание: в настоящее время в версии 16
componentWillMount,componentWillReceiveProps,componentWillUpdateЭти три функции жизненного цикла не удаляются полностью, а новыеUNSAFE_componentWillMount,UNSAFE_componentWillReceiveProps,UNSAFE_componentWillUpdateТри функции, официальный план состоит в том, чтобы полностью удалить эти три функции в версии 17 и оставить только три функции с префиксом UNSAVE_ в целях обратной совместимости, но разработчики должны стараться избегать их использования, а использовать новые. , Функции жизненного цикла заменяют их
На его месте две новые функции жизненного цикла
- static getDerivedStateFromProps
- getSnapshotBeforeUpdate
Мы разделим жизненный цикл React на три этапа, а затем подробно объясним, какие функции вызываются на каждом этапе.
- горная сцена
- фаза обновления
- этап удаления
горная сцена
Фазу монтирования также можно понимать как фазу инициализации компонента, которая заключается в вставке нашего компонента в DOM, что произойдет только один раз.
Вызовы функций жизненного цикла на этом этапе следующие:
- constructor
- getDerivedStateFromProps
componentWillMount/UNSAVE_componentWillMount- render
- componentDidMount
constructor
Конструктор компонента, который должен быть выполнен первым
Если он не определен явно, у нас есть конструктор по умолчанию
Если конструктор определен явно, мы должны выполнить super(props) в первой строке конструктора, иначе мы не сможем получить этот объект в конструкторе, который относится к знаниям ES6.
В конструкторе мы обычно делаем две вещи:
- Инициализировать объект состояния
- Пользовательский метод для привязки этого
constructor(props) {
super(props)
this.state = {
select,
height: 'atuo',
externalClass,
externalClassText
}
this.handleChange1 = this.handleChange1.bind(this)
this.handleChange2 = this.handleChange2.bind(this)
}
Запрещен вызов setState в конструкторе, можно напрямую задать начальное значение состояния
getDerivedStateFromProps
static getDerivedStateFromProps(nextProps, prevState)
Статический метод, поэтому его нельзя использовать в этой функции. Эта функция имеет два параметра props и state, которые относятся к полученным новым параметрам и объекту текущего состояния соответственно. Эта функция возвращает объект для обновления объекта текущего состояния. вернуть ноль, если обновление не требуется
Эта функция будет вызываться при вызове setState и forceUpdate при получении новых реквизитов при монтировании.
В React v16.3 вызывается только при монтировании и получении новых пропсов.Говорят, что это официальная ошибка, которую позже исправили.
Этот метод заменяет предыдущийcomponentWillMount,componentWillReceivePropsиcomponentWillUpdate
Когда мы получаем новые свойства и хотим изменить наше состояние, мы можем использовать getDerivedStateFromProps.
class ExampleComponent extends React.Component {
state = {
isScrollingDown: false,
lastRow: null
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.currentRow !== prevState.lastRow) {
return {
isScrollingDown:
nextProps.currentRow > prevState.lastRow,
lastRow: nextProps.currentRow
}
}
return null
}
}
componentWillMount/UNSAFE_componentWillMount
В версии 16 эти два метода сосуществуют, но в версии 17componentWillMountудалено, только сохраненоUNSAFE_componentWillMount, цель - обратная совместимость, для новых приложений вместо них используйте getDerivedStateFromProps
так какcomponentWillMount/ UNSAFE_componentWillMountОн вызывается перед рендерингом, поэтому даже вызов setState в этом методе не вызовет повторный рендеринг (повторный рендеринг)
render
Самый основной метод в React, компонент должен иметь этот метод
Возвращаемые типы следующие:
- Собственный DOM, такой как div
- Реагировать компоненты
- Фрагмент
- Порталы (слоты)
- Строки и числа, отображаемые как текстовые узлы
- Boolean и null, ничего не будет отображаться
О фрагментах и порталах — это новые дополнения к React 16. Если вы не знаете, вы можете прочитать официальную документацию, которая не будет здесь расширяться.
Функция рендеринга — это чистая функция, которая делает только одно: возвращает то, что нужно отобразить. Она не должна содержать другой бизнес-логики, такой как запрос данных. Для этой бизнес-логики перейдите к componentDidMount и componentDid Обновлять
componentDidMount
Вызывается после загрузки компонента, в это время мы можем получить узел DOM и работать, например, холст, операция svg, запрос сервера, подписка может быть написана в этом, но не забудьте отменить подписку в componentWillUnmount
componentDidMount() {
const { progressCanvas, progressSVG } = this
const canvas = progressCanvas.current
const ctx = canvas.getContext('2d')
canvas.width = canvas.getBoundingClientRect().width
canvas.height = canvas.getBoundingClientRect().height
const svg = progressSVG.current
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('x', 0)
rect.setAttribute('y', 0)
rect.setAttribute('width', 0)
rect.setAttribute('height', svg.getBoundingClientRect().height)
rect.setAttribute('style', 'fill:red')
const animate = document.createElementNS('http://www.w3.org/2000/svg', 'animate')
animate.setAttribute('attributeName', 'width')
animate.setAttribute('from', 0)
animate.setAttribute('to', svg.getBoundingClientRect().width)
animate.setAttribute('begin', '0ms')
animate.setAttribute('dur', '1684ms')
animate.setAttribute('repeatCount', 'indefinite')
animate.setAttribute('calcMode', 'linear')
rect.appendChild(animate)
svg.appendChild(rect)
svg.pauseAnimations()
this.canvas = canvas
this.svg = svg
this.ctx = ctx
}
Вызов setState в componentDidMount запускает дополнительный рендеринг, вызывая функцию рендеринга еще раз, но пользователь этого не воспринимает, потому что он выполняется до того, как браузер обновит экран, но мы должны избегать этого в разработке, потому что это приведет к определенным проблемам с производительностью. , мы должны инициализировать наш объект состояния в конструкторе вместо вызова метода состояния в componentDidMount
фаза обновления
На этапе обновления, когда реквизиты компонента изменяются или внутри компонента вызывается setState или forceUpdate, это происходит несколько раз.
Вызовы функций жизненного цикла на этом этапе следующие:
componentWillReceiveProps/UNSAFE_componentWillReceiveProps- getDerivedStateFromProps
- shouldComponentUpdate
componentWillUpdate/UNSAFE_componentWillUpdate- render
- getSnapshotBeforeUpdate
- componentDidUpdate
componentWillReceiveProps/UNSAFE_componentWillReceiveProps
componentWillReceiveProps(nextProps, prevState) UNSAFE_componentWillReceiveProps(nextProps, prevState)
В версии 16 эти два метода сосуществуют, но в версии 17componentWillReceivePropsбыл удален,UNSAFE_componentWillReceiveProps, цель - обратная совместимость, для новых приложений вместо них используйте getDerivedStateFromProps
Обратите внимание, что когда наш родительский компонент перерисовывается, это также приведет к тому, что наш дочерний компонент вызоветcomponentWillReceiveProps/UNSAFE_componentWillReceiveProps, даже если наши свойства такие же, как и раньше, нам нужно судить в этом методе и вызывать setState, если свойства до и после несовместимы
Во время фазы загрузки эти две функции не будут запущены, и вызов setState и forceUpdate внутри компонента не вызовет эти две функции.
getDerivedStateFromProps
Этот метод уже обсуждался на этапе загрузки, поэтому я не буду повторять его здесь.Помните, что на этапе обновления этот метод будет вызываться независимо от того, получим ли мы новое свойство, вызовем setState или вызов forceUpdate.
shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState)
Есть два параметра nextProps и nextState, которые представляют новое свойство и состояние после изменения и возвращают логическое значение: true означает, что повторная визуализация будет запущена, false означает, что повторная визуализация не будет запущена, а значение по умолчанию возвращает истину
Обратите внимание, что этот метод не запускается, когда мы вызываем forceUpdate.
Поскольку по умолчанию возвращается true, то есть пока будут получены новые свойства и будет вызван setState, будет срабатывать повторный рендеринг, который принесет определенные проблемы с производительностью, поэтому нам нужно сравнить this.props с nextProps и this. state с nextState, чтобы решить, следует ли возвращать false, чтобы уменьшить повторный рендеринг
Тем не менее, официально рекомендуется использовать PureComponent для уменьшения количества повторных рендеров вместо ручного написания кода shouldComponentUpdate Конкретный выбор полностью зависит от разработчика.
В будущих версиях shouldComponentUpdate возвращает false, что все еще может привести к повторному рендерингу компонента, так сказал официальный представитель.
Currently, if shouldComponentUpdate() returns false, then UNSAFE_componentWillUpdate(), render(), and componentDidUpdate() will not be invoked. In the future React may treat shouldComponentUpdate() as a hint rather than a strict directive, and returning false may still result in a re-rendering of the component.
componentWillUpdate/UNSAFE_componentWillUpdate
componentWillUpdate(nextProps, nextState)
UNSAFE_componentWillUpdate(nextProps, nextState)
В версии 16 эти два метода сосуществуют, но в версии 17componentWillUpdateбыл удален,UNSAFE_componentWillUpdate, цель - обратная совместимость
В этом методе нельзя вызывать setState, так как если можно перейти к этому методу, значит, shouldComponentUpdate вернет true, в это время определено следующее состояние state, и ререндеринг рендера будет выполнен сразу, иначе весь жизненный цикл будет хаотичным, здесь также невозможно запросить некоторые сетевые данные, потому что при асинхронном рендеринге это может вызвать несколько сетевых запросов, вызывая некоторые проблемы с производительностью.
Если вы сохраняете положение прокрутки в этом методе, это также неточно или из-за проблемы асинхронного рендеринга.Если вам нужно получить положение прокрутки, пожалуйста, вызовите getSnapshotBeforeUpdate
render
Фаза обновления также будет запущена, а фаза загрузки уже обсуждалась, поэтому повторяться не буду.
getSnapshotBeforeUpdate
getSnapshotBeforeUpdate(prevProps, prevState)
Этот метод вызывается после рендеринга и перед componentDidUpdate. Он имеет два параметра, prevProps и prevState, которые представляют предыдущие свойства и предыдущее состояние. Эта функция имеет возвращаемое значение, которое будет передано в componentDidUpdate в качестве третьего параметра. Если вы это сделаете не хотите возвращаемое значение, пожалуйста, верните null, иначе в консоли появится предупреждение
И этот метод нужно использовать вместе с componentDidUpdate, иначе в консоли тоже будет предупреждение
Как упоминалось ранее, этот метод используется вместоcomponentWillUpdate/UNSAVE_componentWillUpdate, ниже приведен пример для иллюстрации:
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// If we have a snapshot value, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
// (snapshot here is the value returned from getSnapshotBeforeUpdate)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}
componentDidUpdate
componentDidUpdate(prevProps, prevState, snapshot)
Этот метод вызывается после метода getSnapshotBeforeUpdate и имеет три параметра prevProps, prevState, snapshot, указывающих предыдущие реквизиты, предыдущее состояние и моментальный снимок. Третий параметр возвращается функцией getSnapshotBeforeUpdate.
В этой функции мы можем манипулировать DOM, инициировать серверные запросы и setState, но будьте осторожны, чтобы использовать оператор if для управления, иначе это приведет к бесконечному циклу.
этап удаления
Этап удаления, когда наш компонент удаляется или уничтожается
На данном этапе существует только одна функция жизненного цикла:
- componentWillUnmount
componentWillUnmount
Она будет вызываться, когда наш компонент будет выгружен или уничтожен.Мы можем использовать эту функцию для очистки некоторых таймеров, отмены сетевых запросов, очистки недопустимых элементов DOM и другой работы по очистке мусора.
Будьте осторожны, чтобы не вызвать setState в этой функции, потому что компонент не будет повторно отображать
Наконец
Ознакомьтесь с жизненным циклом React v16.4
Ваша награда - мотивация для моего письма