React, как мы все знаем, меняется. Как фронтенд-разработчику с опытом работы с React последние 3 года, продать мне эти изменения было довольно сложно.
Сегодня я здесь как продавец, а не как покупатель, надеюсь, я поймаю вас в лихорадке, которая у меня возникла, когда я пойму, что стоит за всеми этими изменениями :)

После того, как команда React объявила о хуках и выдвинула функциональные компоненты как решение всех наших проблем, у меня в голове возникла эта мысль: почему мы должны использовать React defaultProps, а не значения по умолчанию ES6 для функциональных компонентов? Затем я нашел этот RFC, который в значительной степени говорит о том, что основная команда React думает об этой идее.

В этом посте я расскажу о своих мыслях и поделюсь некоторыми выводами о производительности.
Я начну с простого объяснения, касающегося defaultProps и значений по умолчанию ES6. Чтобы избежать путаницы, давайте решим вызвать React defaultProps React def. значения и значения по умолчанию ES6 ES6 def. ценности. Если вы уже знакомы с синтаксисом, не стесняйтесь переходить к выводам.

React def. ценности:

Начиная с React v15.5, проверка типа среды выполнения для props компонента перенесена в единый пакет под названием prop-types. Этот пакет дает нам возможность ввести проверку свойств компонента и присвоить ему значения по умолчанию, например, давайте посмотрим на компонент Greet:

const Greet = ({firstName, lastName}) => {
  return (<div>{`Hi ${firstName} ${lastName}`}!</div>)
}
Greet.propTypes = {
  firstName: PropTypes.string,
  lastName: PropTypes.string
};

Если мы попытаемся отрендерить Greet, не задав ему реквизита:

const Header = props => {
  return <React.Fragment>
    <Logo/>
    <Greet/>
  </React.Fragment>
}

У нас получится что-то вроде этого:

Hi undefined undefined!

defaultProps позволяет нам избежать этого сценария, установив значения по умолчанию для props:

Greet.defaultProps = {
  firstName: 'John',
  lastName: 'Doe'
};

поэтому, если не передать соответствующие реквизиты, мы получим:

Hi John Doe!

ES6 def. ценности:

Другой вариант, который мы можем использовать в только функциональных компонентах, - это установка значений по умолчанию с синтаксисом назначения ES6 Destructuring.
Давайте возьмем компонент Greet, который мы создали выше, и изменим его, чтобы он содержал значения по умолчанию. .

const Greet = ({firstName = 'John', lastName = 'Doe'}) => {
  return (<div>{`Hi ${firstName} ${lastName}`}!</div>)
}

Вот так просто.
Так что же нам использовать?

Поскольку все связано с программированием, это компромисс, давайте разберемся, почему.

Преимущества и недостатки настроек React по умолчанию:

Хотя использование defaultProps является лучшей практикой на данный момент, похоже, что это изменится в следующих версиях React.
Основное преимущество defaultProps в том, что он дает нам унифицированный способ установки значений по умолчанию для свойств в обоих компонентах класса. и функциональные компоненты. Второе преимущество состоит в том, что синтаксис прост и понятен.
Основная проблема с defaultProps заключается в его реализации.
Давайте посмотрим на реализацию React.createElement в последней стабильной версии (16.8.6).

Мы видим, что некоторые вещи происходят при вызове createElement с объектом props, но основная проблема - это проверка defaultProps. Если у нас есть defaultProps, мы перебираем их и проверяем, есть ли у нас уже значение в объекте props. Если у нас нет значения, мы присваиваем ему значение по умолчанию. Это происходит каждый раз, когда мы звоним createElement.
Давайте посмотрим на небольшой пример синхронизации, который я взял с только что созданным компонентом Greet (тест проводился в разрабатываемой сборке React).
Все, что я сделал, это добавил console.time() в начале createElement и console.timeEnd() в конце.

With defaultProps, createElement time: 0.01123046875ms
Without defaultProps, createElement time: 0.003662109375ms

Это в три раза медленнее для этого простого компонента, и он содержит только два defaultProps!
Вкратце, это не означает, что добавление defaultProps увеличит время рендеринга на три, оно просто добавляет несколько миллисекунд при повторении значений по умолчанию.

Преимущества и недостатки настроек ES6 по умолчанию:

Основное преимущество значений по умолчанию заключается в том, что это собственный синтаксис, добавленный в ES6 и поддерживаемый почти во всех браузерах (кроме IE11) как часть деструктурирующего назначения.
На мой взгляд, большая проблема со значениями по умолчанию заключается в том, что они создают разница между тем, как мы устанавливаем значения по умолчанию в компонентах класса и как мы устанавливаем их в функциональных компонентах, поскольку установка значения по умолчанию для свойства недоступна в классе, компоненты старого класса все равно должны будут использовать старый propTypes способ, тем самым создавая еще одно различие между этими двумя типами компонентов. Эта проблема со временем исчезнет, ​​так как использование компонентов класса должно уменьшаться с перехватами.

Для решения второй проблемы нам придется немного изменить компонент Greet,
давайте изменим компонент, чтобы он принимал пользовательский объект вместо firstName и lastName.

const Greet = ({user = { firstName: 'John', lastName: 'Doe' }}) => {
  return (<div>{`Hi ${user.firstName} ${user.lastName}`}</div>)
}

В чем проблема с созданным нами примером? Правильно, неизменность. Объект, который мы создали в качестве значения по умолчанию, будет воссоздаваться при каждом вызове функции, поэтому, если мы передадим его дочернему компоненту, компонент будет каждый раз получать новую ссылку и вызывать рендеринг для каждого родительского рендера.
Чтобы решить эту проблему, нам нужно будет создать глобальное значение по умолчанию как const, чтобы ссылка не изменилась:

const defaultUser = { firstName: 'John', lastName: 'Doe' };
const Greet = ({user = defaultUser}) => {
  return (<div>{`Hi ${user.firstName} ${user.lastName}`}</div>)
}

При использовании значений по умолчанию в последних версиях браузеров, которым не требуется переносить деструктурирующее назначение, это может даже привести к уменьшению размера пакета. С другой стороны, при использовании его в браузерах, которым необходимо его транспилировать, это может привести к большему размеру пакета, поскольку деструктуризация значений по умолчанию для присвоения транспилирует довольно странно.
Я сделал небольшой пример, основанный на CRA, только с prop-types и styled-components добавлены. Пример состоит из 10 компонентов, каждый из которых содержит defaultProps.
Давайте посмотрим на сравнение размеров пакетов после сжатия:

Без defaultProps и преобразования значений по умолчанию: 55,969 КБ
Без defaultProps и без преобразования значений по умолчанию: 55,945 КБ
С defaultProps: 55,979 КБ

Похоже, разница в размере комплекта минимальна.

Подводя итоги:

  • React def. values ​​позволяет нам иметь унифицированный способ установки значений по умолчанию.
  • React def. значения будут тем медленнее, чем больше значений по умолчанию вы установите.
  • ES6 def. Значения могут уменьшить размер вашего пакета при развертывании в браузерах, в которых уже включено назначение деструктуризации.
  • При использовании ES6 def. values, вы должны помнить о подводных камнях и заранее создавать непримитивные значения, чтобы они не вызывали рендеринг дочерних элементов.
  • Команда React остановилась на ES6 def. values ​​как способ установки значений по умолчанию для функциональных компонентов. Предупреждение уже было добавлено как часть процесса устаревания defaultProps в функциональных компонентах.

Похоже, мы увидим изменения, подобные тем, о которых я говорил, в следующей версии React, и все это часть того, чтобы сделать React лучше для нас, разработчиков, и для наших пользователей. Команда React усердно работает над решением проблем с производительностью и изменением того, как мы видим Интернет сейчас.
Продолжайте в том же духе, команда React

Надеюсь, я продал его хорошо, но если у вас есть какие-либо вопросы, не стесняйтесь спрашивать.
Я здесь и тоже в твиттере.
Спасибо, что прочитали!