Компоненты React отлично подходят для выражения всех вещей, о которых может заботиться часть нашего приложения. Это включает в себя внешнюю информацию, которая может потребоваться нашему компоненту для работы в качестве потребителя нашего компонента. Вот ряд соображений, которые я нашел полезными при написании и управлении prop-types
.
Пусть реализация потерпит неудачу
Эта концепция объясняет, почему prop-types
выдает предупреждение для начала. Часто, как авторы API, мы хотим обеспечить хорошее восстановление, когда наш клиент не может предоставить нам данные, в которых мы больше всего нуждаемся. Если мы делаем слишком много для восстановления, мы теряем возможность обучить наших потребителей тому, что мы ожидаем от них, чтобы правильно использовать наш API.
Например,
class Title extends React.Component { static propTypes = { title: PropTypes.string } render() { if (!this.props.title) { return null } return ( <h1>{title}</h1> ) } }
// or written as a pure function const Title = ({ title }) => ( { title && <h1>{title}</h1> } )
Title.propTypes = { title: PropTypes.string }
В предыдущих примерах компонент Title
«защищает» от того, предоставлен ли заголовок или нет, и определяет, возвращать ли какой-либо нулевой артефакт в качестве типа возвращаемого значения метода визуализации. Несмотря на кажущуюся безобидность, мы упускаем возможность сделать здесь несколько вещей.
Сократите объем работы, предотвратив любое построение или вызов.
Описанный ранее шаблон говорит о том, что запускать или конструировать наш Title
компонент некорректно - это нормально, поскольку Title
просто возвращает null
или undefined
. Как расширение компонента, это означает, что все методы жизненного цикла будут запущены и рассмотрены для согласования React в будущих циклах.
Как функция, это означает то же самое в отношении согласования, всегда возвращая какой-то артефакт, хотя мы, вероятно, не должны этого делать.
class Title extends React.Component { static propTypes = { title: PropTypes.string.isRequired } render() { return ( <h1>{title}</h1> ) } }
// or written as a pure function const Title = ({ title }) => ( <h1>{title}</h1> ) Title.propTypes = { title: PropTypes.string.isRequired }
Чтобы выделить ключевые различия, мы применили свойство isRequired
к нашему полю заголовка. React проверит это и warn
наших потребителей, что наш Title
компонент не получил реквизиты, необходимые для правильного поведения. В этом случае мы ожидаем, что наш Title
компонент вернет нам только заголовок, помеченный как H1
.
Предупреждение должно намекать разработчику, что они не должны рисовать компонент Title
, когда нет заголовка, который нужно рисовать. Обычно это выполняется при простой оценке компонента, содержащего наш <Title />
.
class ContainerComponent extends React.Component { static propTypes = { title: PropTypes.string } static defaultProps = { title: '' }
render ( <div> { this.props.title && <Title title={this.props.title} /> } </div> ) }
Что достигается, так это то, что компонент представления должен меньше заботиться о том, как обращаться с его реализацией, и больше о том, для чего он предназначен. Кроме того, полагаясь на prop-types
для предоставления обратной связи разработчику, мы поощряем улучшенное управление кодом за счет установки значений по умолчанию потребителем, сокращая при этом объем работы, выполняемой приложением, путем создания экземпляров компонентов в неподходящее время.
Управление избыточными типами опор
PropTypes
- это здорово, но сложно реализовать через компоненты контейнера. Давайте снова посмотрим на пример Title
:
// Title.js const Title = ({ title }) => ( <h1>{title}</h1> ) Title.propTypes = { title: PropTypes.string.isRequired }
export Title
// App.js class App extends React.Component { static propTypes = { title: PropTypes.string } static defaultProps = { title: '' } render() { return ( <div> { this.props.title && <Title title={this.props.title} /> } </div> ) } }
Если вы писали много кода на React, это может показаться вам знакомым. Проблема, которую мы здесь рассматриваем, заключается в том, сколько раз мы определяем одну и ту же prop-type
проверку из дочерних компонентов в содержащих компонентах. Часто это приводит к написанию большого количества повторяющегося кода и добавляет, даже больше, работы, когда дело доходит до удаления компонентов из контейнеров.
Есть несколько способов справиться с этим:
export/import propTypes
В конце концов, мы используем модули, и некоторые люди уже этим занимаются:
// Title.js const propTypes = { title: PropTypes.string.isRequired }
const Title = ({ title }) => ( <h1>{title}</h1> )
Title.propTypes = propTypes
export propTypes export Title
// App.js import { Title, propTypes as titlePropTypes } from './Title'
class App extends React.Component { static propTypes = Object.assign(titlePropTypes, {}) static defaultProps = { title: '' } render() { return ( <div> { this.props.title && <Title title={this.props.title} /> } </div> ) } }
Это отличное начало, но оно требует, чтобы каждый составной компонент управлял своими prop-types
одинаковым образом. Но если мы более подробно рассмотрим, как prop-types
определяются и применяются к компоненту React, мы должны признать, что всякий раз, когда мы import
компонент, для начала, мы получаем его ассоциированный prop-types
бесплатно. prop-types
считаются static
свойствами компонента React, что означает, что вам не требуется создавать экземпляр компонента, чтобы понять, что это prop-types
.
Составление опорных типов из нескольких компонентов
// Title.jsconst propTypes = { title: PropTypes.string.isRequired }
const Title = ({ title }) => ( <h1>{title}</h1> )
Title.propTypes = propTypes
export Title
// App.js import { Title } from './Title'
class App extends React.Component { static propTypes = Object.assign(Title.propTypes, {}) static defaultProps = { title: '' } render() { return ( <div> { this.props.title && <Title title={this.props.title} /> } </div> ) } }
Здесь мы внесли небольшую корректировку в то, как мы наследуем prop-types
от дочернего или презентационного компонента, чтобы заставить наш компонент-контейнер.
минусы?
Когда мы думаем об управлении prop-type
, нам приятно знать одну вещь: «О каких типах свойств должен заботиться мой контейнер?». Не записывая каждый prop-type
в контейнере, мы теряем разборчивость совокупности полей прямо в нашем коде. Можно сказать, что этот метод уменьшает количество оптических элементов и требует, чтобы разработчик углубился в код компонента, чтобы понять, какие реквизиты необходимо предоставить контейнеру.
Повторная проверка также может быть жалобой. Эта практика приводит к меньшему количеству свойств по умолчанию в презентационных компонентах и большему количеству свойств по умолчанию в наших контейнерах, что делает более жесткие API в презентационных компонентах, что упрощает понимание того, как реализовать надлежащим образом. Меньшее количество свойств по умолчанию, определенных в презентационных компонентах, также приводит к более простой отладке свойств по умолчанию. Свойства по умолчанию могут быть проблематичными при реализации некоторого API, и мы не уверены, где и что задает свойство.
Должны ли контейнеры вообще заботиться?
И последнее наблюдение, которым я поделюсь: должен ли контейнер вообще проверять дочерний API? В этом случае я действительно мог бы пойти по любому пути, но если компонент контейнера заботится о некотором внешнем контенте, который должен быть предоставлен, как правило, из API, тогда да, я бы проголосовал за включение контракта API, определенного prop-types
, который должен быть определен.
Однако в случае, когда наш контейнер является тем, который предоставляет контент для презентационного компонента, нет смысла также включать дочернюю prop-type
валидацию.
Ясно, что здесь есть несколько вариантов, которые помогут нам управлять prop-types
СУХИМ и ответственным образом. Я бы посоветовал вам изучить, примерить эти выкройки на размер.
Копать этот пост? Хлопнуть в ладоши
Если бы вы могли пожалеть аплодисменты, мы были бы очень признательны! Ваша поддержка и поддержка - это то, что заставляет нас работать над созданием значимого для вас контента.
Спасибо за внимание, до встречи в следующей публикации.
Первоначально опубликовано на www.jjmasse.com 24 ноября 2017 г.