Если вы опытный инженер React, у вас может возникнуть идея закрыть страницу, если вы прочитали эту статью о жизненном цикле React и прочитали бесчисленное количество статей о жизненном цикле React.
Пожалуйста, не торопитесь, я хочу поговорить о чем-то другом, из будущего.
Обновление 2018.5.24:
Сегодня вышел React 16.4.
getDerivedStateFromProps
Время триггера было изменено - оно срабатывало только тогда, когда родительский компонент повторно отображает его.getDerivedStateFromProps
, теперь он будет срабатывать при каждом рендеринге, включая сам себяsetState
. Это изменение еще больше отличает метод отcomponentWillReceiveProps
, который больше подходит для асинхронного рендеринга.
Как мы все знаем, существует бесчисленное множество статей об анализе, руководстве и подробной интерпретации жизненного цикла React. Так почему я должен переписывать его снова? потому чтоЖизненный цикл React вот-вот изменится! В настоящее время команда Rac React работает над созданием асинхронного механизма рендеринга для дальнейшего улучшения производительности рендеринга реагирования. В процессе они внесли несколько изменений в жизненный цикл, чтобы лучше удовлетворить потребности асинхронного рендеринга.
Короче говоря, 3 метода жизненного цикла были удалены и добавлены еще 2:
+: 新增 -: 删除 ?: 有变化
- componentWillMount
render
componentDidMount
- componentWillReceiveProps
+ static getDerivedStateFromProps
shouldComponentUpdate
- componentWillUpdate
+ getSnapshotBeforeUpdate
? componentDidUpdate
componentWillUnmount
class Example extends React.Component {
static getDerivedStateFromProps(nextProps, prevState) {
// 这一生命周期方法是静态的,它在组件实例化或接收到新的 props 时被触发
// 若它的返回值是对象,则将被用于更新 state ;若是 null ,则不触发 state 的更新
// 配合 `componentDidUpdate` 使用,这一方法可以取代 `componentWillReceiveProps`
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// 该方法在实际改动(比如 DOM 更新)发生前的“瞬间”被调用,返回值将作为 `componentDidUpdate` 的第三个参数
// 配合 `componentDidUpdate` 使用,这一方法可以取代 `componentWillUpdate`
}
componentDidUpdate(props, state, snaptshot) {
// 新增的参数 snapshot 即是之前调用 getSnapshotBeforeUpdate 的返回值
}
}
конкретное объяснение
-componentWillMount
Этот метод жизненного цикла был удален по следующим причинам:
- В будущем механизме асинхронного рендеринга один экземпляр компонента может также вызывать этот метод несколько раз.
- его можно распространять на
constructor
а такжеcomponentDidMount
Приведу несколько примеров:
Привязка события, асинхронный запрос
Некоторые неопытные разработчики могут по ошибке поместить код для привязки событий и асинхронной выборки данных вcomponentWillMount
в, что приводит к
А. Рендеринг на стороне сервера активирует этот метод жизненного цикла, но запрос делается напрасно, поскольку асинхронно полученные данные часто игнорируются или серверная сторона не запускаетcomponentWillUnmount
Невозможно отменить мониторинг событий, что приводит к утечке памяти
б) сочетать1.
, несколько вызовов приведут к дублированию запросов или дублированию слушателей, что также может привести к утечке памяти.
Лучшие практики:
class ExampleComponent extends React.Component {
state = {
subscribedValue: this.props.dataSource.value,
externalData: null,
};
componentDidMount() {
// 这里只触发一次,可以安全地进行 异步请求、事件绑定
this.asyncRequest = asyncLoadData().then(
externalData => {
this.asyncRequest = null;
this.setState({externalData});
}
);
this.props.dataSource.subscribe(this.handleSubscriptionChange);
}
componentWillUnmount() {
if (this.asyncRequest) this.asyncRequest.cancel();
// 事件绑定在客户端才进行,且只进行一次,在这里可以安全地解绑
this.props.dataSource.unsubscribe(this.handleSubscriptionChange);
}
handleSubscriptionChange = dataSource => {
this.setState({ subscribedValue: dataSource.value });
};
}
-componentWillReceiveProps & +getDerivedStateFromProps
Давайте посмотрим на общийcomponentWillReceiveProps
Применение:
class ExampleComponent extends React.Component {
state = {
isScrollingDown: false,
};
componentWillReceiveProps(nextProps) {
if (this.props.currentRow !== nextProps.currentRow) {
// 检测到变化后更新状态、并请求数据
this.setState({
isScrollingDown: nextProps.currentRow > this.props.currentRow,
});
this.loadAsyncData()
}
}
loadAsyncData() {/* ... */}
}
В этом коде нет ничего плохого, но есть лучшие способы написать его. когда используешьgetDerivedStateFromProps
, что можно записать как:
class ExampleComponent extends React.Component {
state = {
isScrollingDown: false,
lastRow: null,
};
static getDerivedStateFromProps(nextProps, prevState) {
// 不再提供 prevProps 的获取方式
if (nextProps.currentRow !== prevState.lastRow) {
return {
isScrollingDown: nextProps.currentRow > prevState.lastRow,
lastRow: nextProps.currentRow,
};
}
// 默认不改动 state
return null;
}
componentDidUpdate() {
// 仅在更新触发后请求数据
this.loadAsyncData()
}
loadAsyncData() {/* ... */}
}
Видно, что в этом случае разработчики более «стихийно» возьмут на себяcomponentDidUpdate
Напишите код, который запускает асинхронные запросы (потому что выбора нет :P), избегая проблемы — внешний компонент часто обновляется несколько раз и передает несколько разных реквизитов, а компонент группирует эти обновления и запускает только одно обновление самого себя, поэтому написание первого приведет к ненужным асинхронным запросам, а второе более ресурсоэффективно.
-componentWillUpdate & +getSnapshotBeforeUpdate
componentWillUpdate
Обычно используется для записи состояния DOM перед обновлением в сочетании с состоянием после обновления.componentDidUpdate
Необходимая обработка выполняется над вновь полученным состоянием DOM. Появление асинхронного рендеринга делаетcomponentWillUpdate
Время триггера (оно было запрещено при асинхронном рендеринге, но здесь мы предполагаем, что оно все еще существует) такое же, какcomponentDidUpdate
Интервал времени триггера велик, потому что асинхронный рендеринг может приостановить обновление этого компонента в любой момент. В результате предыдущий подход был бы менее стабильным, так как DOM мог измениться из-за поведения пользователя.
Для этого React предоставляетgetSnapshotBeforeUpdate
. Его время срабатывания — это «момент» до того, как React произведет модификацию (обычно обновит DOM), так что полученная здесь информация о DOM будет еще более достоверной.componentWillUpdate
Более надежный. Кроме того, его возвращаемое значение будет передано в качестве третьего параметраcomponentDidUpdate
, преимущество этого очевидно — разработчику не нужно сохранять сгенерированные данные, чтобы согласовать состояние до и после рендеринга на экземпляре компонента, и их можно уничтожить, когда они израсходуются.
Кратко обобщить
С тех пор как React достиг 16-го номера версии, это как сидеть на ракете, а эволюция производительности и API впечатляет. В ближайшем будущем будет официально представлен асинхронный рендеринг, что принесет еще один прорыв в производительности рендеринга. В изменениях жизненного цикла, обсуждаемых в этой статье, вы можете увидеть добрые намерения команды React подготовить почву для этого изменения — удаление старых API-интерфейсов, предупреждение или незаметное принуждение разработчиков к следованию лучшим методам разработки. Начиная с v16.3 старый API будет постепенно заменяться, а когда v17 будет полностью заброшен, все здесь смогут начать рассматривать возможность обновления своих проектов!
Ссылка на ссылку: https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html