Как вы решите, как вы выбираете между этими тремя в зависимости от назначения / размера / реквизита / поведения наших компонентов?
Расширение из 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>
}
}
В конце я бы сказал, что «тупой», «не имеющий состояния» и «чистый» - это совершенно разные понятия, которые иногда могут перекрываться, но не обязательно, в зависимости, в основном, от вашего варианта использования.