Назад

componentWillReceiveProps умер! Да здравствует getDerivedStateFromProps!

Если вы вдруг не заметили, то 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.

N команд для начинающих, которые нужно знать, чтобы работать с git

Зачем мне фотоаппарат в 2018?