Если вы вдруг не заметили, то componentWillReceiveProps умер. Точнее не совсем, но в React 17 точно умрет. Пока вы можете его использовать как и раньше, но разработчики пометили его как устаревший и вместо него рекомендуют использовать getDerivedStateFromProps. Почему же так и как с этим жить? Давайте вместе разберемся.
Для начала разберемся чем не угодил метод componentWillReceiveProps? Если верить информации в официальном блоге, то проблема в том, что люди часто использовали этот метод не по назначению, что приводило к проблемам. Именно из-за этого от него было решено отказаться. Каких-то конкретных примеров "неправильного использования" я не нашел, но недавно я слышал мнение о том, что сейчас команда React работает над, так называемым, асинхронным рендерингом. Так вот, проблема была в том, что слово will подталкивало людей к мысли, что подобные хуки идеальное место, чтобы сделать асинхронный запрос, хотя это не так. Проблему это, кстати, не решило, но что сделано, то сделано. Вот в этой ветке Дэм Абрамов дискутирует на эту тему (думаю не только в ней).
Как более безопасную альтернативу предлагается использовать методы componentDidUpdate и getDerivedStateFromProps. Если с первых все более-менее понятно, то второй, лично у меня, вызвал сперва некое недоумение.
Во-первых, в отличии от componentWillReceiveProps, этот метод вызывается как и при первоначальной отрисовке, так и при перерисовках. Но это не отменяет того, что вы все еще должны задавать изначальное состояние. В дополнение стоит сказать, что если родительский компонент вызывает перерисовку, то этот метод будет вызван даже если, фактически, свойства не изменились.
Во-вторых, это статический метод, который на вход получает новые свойства (nextProps) и предыдущее состояние (prevState). И если вам это ни о чем не говорит, то, проще говоря, ключевое слово this
там не доступно. И вот тут, возможно, вы, как и я, начали паниковать. Как же я буду вызывать this.setState
, если но недоступно? Для решения этой задачи вам нужно провернуть такой фокус. Если вы вернули null, то это значит, что состояние не обновилось, а если же вернули объект, то эффект такой же, как от вызова this.setState
.
Сказать, что я в восторге от этих нововведений я не могу. Это полностью ломает те шаблоны, к которым я привык. Если раньше вы могли сравнить this.props.somenthing
и nextProps.something
, то теперь нам предлагают ложить свои свойства, которые необходимы для вычисления состояния, в само состояние. Почему же тогда не передать prevProps
как аргумент? Да потому, что при первоначальной отрисовке аргумент prevProps
будет не определен и каждый раз придется проверять, что он определен, прежде чем оперировать с ним. Ниже приведены конкретные примеры.
// С использованием 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,
});
}
}
}
// С использованием 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;
}
}
Стоит отметить, что если вы определите componentWillReceiveProps и getDerivedStateFromProps одновременно (в одном компоненте), то вызван будет только getDerivedStateFromProps.
Надеюсь я помог вам пролить свет на темные моменты нового API React. На моей памяти это одни из самых серьезных изменений за длительное время в React.