Как вы решите, как вы выбираете между этими тремя в зависимости от назначения / размера / реквизита / поведения наших компонентов?
Расширение из React.PureComponentили React.Componentс помощью пользовательского shouldComponentUpdateметода влияет на производительность. Использование функциональных компонентов без сохранения состояния является «архитектурным» выбором и не дает никаких преимуществ с точки зрения производительности (пока).
Для простых компонентов, предназначенных только для презентаций, которые необходимо легко использовать повторно, предпочитайте функциональные компоненты без сохранения состояния. Таким образом, вы уверены, что они не связаны с реальной логикой приложения, что их очень легко протестировать и у них нет неожиданных побочных эффектов. Исключение составляют случаи, когда по какой-то причине их много или вам действительно нужно оптимизировать их метод рендеринга (поскольку вы не можете определить shouldComponentUpdateфункциональный компонент без состояния).
Расширьте, PureComponentесли вы знаете, что ваш вывод зависит от простых реквизитов / состояния («простой», что означает отсутствие вложенных структур данных, так как PureComponent выполняет поверхностное сравнение) И вам нужно / можно получить некоторые улучшения производительности.
Расширьте Componentи внедрите свой собственный, shouldComponentUpdateесли вам нужно некоторое повышение производительности, выполняя пользовательскую логику сравнения между следующим / текущим реквизитом и состоянием. Например, вы можете быстро выполнить глубокое сравнение, используя lodash # isEqual:
class MyComponent extends Component {
shouldComponentUpdate (nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
}
}
Кроме того, реализация вашей собственной shouldComponentUpdateили выход из нее PureComponentявляется оптимизацией, и, как обычно, вы должны начать изучать ее, только если у вас есть проблемы с производительностью ( избегайте преждевременной оптимизации ). Как правило, я всегда стараюсь выполнять эти оптимизации после того, как приложение находится в рабочем состоянии, причем большинство функций уже реализовано. Намного легче сосредоточиться на проблемах производительности, когда они действительно мешают.
Подробнее
Функциональные компоненты без состояния:
Они определяются только с помощью функции. Поскольку для компонента без состояния не существует внутреннего состояния, вывод (то, что отображается) зависит только от реквизитов, заданных в качестве входных данных для этой функции.
Плюсы:
Простейший способ определения компонента в React. Если вам не нужно управлять каким-либо состоянием, зачем беспокоиться о классах и наследовании? Одно из основных различий между функцией и классом заключается в том, что с функцией вы уверены, что вывод зависит только от ввода (а не от истории предыдущих выполнений).
В идеале в вашем приложении вы должны стремиться иметь как можно больше компонентов без сохранения состояния, поскольку это обычно означает, что вы переместили свою логику за пределы слоя представления и переместили ее в нечто вроде избыточности, что означает, что вы можете проверить свою настоящую логику без необходимости что-либо визуализировать. (гораздо проще тестировать, больше использовать повторно и т. д.).
Минусы:
Нет методов жизненного цикла. У вас нет возможности определить componentDidMountи других друзей. Обычно вы делаете это в родительском компоненте, находящемся выше в иерархии, чтобы вы могли превратить всех потомков в детей без состояния.
Нет способа вручную контролировать, когда требуется повторная визуализация, поскольку вы не можете определить shouldComponentUpdate. Повторный рендеринг происходит каждый раз, когда компонент получает новые реквизиты (нет способа поверхностного сравнения и т. Д.). В будущем React может автоматически оптимизировать компоненты без сохранения состояния, а сейчас есть некоторые библиотеки, которые вы можете использовать. Поскольку компоненты без состояния - это просто функции, в основном это классическая проблема «запоминания функций».
Ссылки не поддерживаются: https://github.com/facebook/react/issues/4936
Компонент, который расширяет класс PureComponent VS Нормальный компонент, который расширяет класс Component:
React имел обыкновение иметь, PureRenderMixinвы могли присоединиться к классу, определенному с использованием React.createClassсинтаксиса. Миксин будет просто определять shouldComponentUpdateвыполнение поверхностного сравнения между следующим реквизитом и следующим состоянием, чтобы проверить, изменилось ли что-нибудь там. Если ничего не меняется, то нет необходимости выполнять повторную визуализацию.
Если вы хотите использовать синтаксис ES6, вы не можете использовать миксины. Поэтому для удобства React представил PureComponentкласс, от которого вы можете наследовать, а не использовать Component. PureComponentпросто реализует shouldComponentUpdateтаким же образом PureRendererMixin. Это в основном удобство, поэтому вам не нужно реализовывать это самостоятельно, поскольку поверхностное сравнение между текущим / следующим состоянием и реквизитом, вероятно, является наиболее распространенным сценарием, который может дать вам быстрый выигрыш в производительности.
Пример:
class UserAvatar extends Component {
render() {
return <div><img src={this.props.imageUrl} /> {{ this.props.username }} </div>
}
}
Как видите, результат зависит от props.imageUrlи props.username. Если в родительском компоненте вы выполняете рендеринг <UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" />с одинаковыми реквизитами, React будет вызывать renderкаждый раз, даже если результат будет точно таким же. Однако помните, что React реализует dom diffing, поэтому DOM фактически не будет обновляться. Тем не менее, выполнение DOM Diffing может быть дорогостоящим, поэтому в этом случае это будет пустая трата времени.
Если UserAvatarкомпонент расширяется PureComponent, выполняется поверхностное сравнение. И потому, что реквизиты и nextProps одинаковы, renderне будет вызываться вообще.
Примечания к определению «чистый» в React:
В общем, «чистая функция» - это функция, которая всегда оценивает один и тот же результат при одинаковых входных данных. Вывод (для React, это то, что возвращается renderметодом) не зависит от какой-либо истории / состояния и не имеет побочных эффектов (операций, которые изменяют «мир» вне функции).
В React компоненты без сохранения состояния не обязательно являются чистыми компонентами в соответствии с приведенным выше определением, если вы называете компонентом без состояния компонент, который никогда не вызывает this.setStateи не использует this.state.
Фактически, PureComponentвы все равно можете выполнять побочные эффекты во время методов жизненного цикла. Например, вы можете отправить ajax-запрос внутрь componentDidMountили выполнить некоторое вычисление DOM, чтобы динамически настроить высоту div внутри render.
Определение «тупых компонентов» имеет более «практическое» значение (по крайней мере, в моем понимании): тупому компоненту «говорят», что делать с родительским компонентом через реквизиты, и он не знает, как это делать, но использует реквизиты. обратные вызовы вместо.
Пример «умного» AvatarComponent:
class AvatarComponent extends Component {
expandAvatar () {
this.setState({ loading: true });
sendAjaxRequest(...).then(() => {
this.setState({ loading: false });
});
}
render () {
<div onClick={this.expandAvatar}>
<img src={this.props.username} />
</div>
}
}
Пример "тупой" AvatarComponent:
class AvatarComponent extends Component {
render () {
<div onClick={this.props.onExpandAvatar}>
{this.props.loading && <div className="spinner" />}
<img src={this.props.username} />
</div>
}
}
В конце я бы сказал, что «тупой», «не имеющий состояния» и «чистый» - это совершенно разные понятия, которые иногда могут перекрываться, но не обязательно, в зависимости, в основном, от вашего варианта использования.