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