Что вы делаете, когда у вас есть «одинаковые, но разные» компоненты, и вы хотите их повторно использовать?

Давайте посмотрим на пример

Кнопка загрузки

У нас есть 2 очень похожих компонента:

Они оба о загрузке файлов. Однако одна кнопка используется для создания словаря, а другая - данных. Различия между Data и Dictionary на данный момент не актуальны.

Обе кнопки имеют аналогичное поведение. Они открывают файловую систему для выбора файлов. При их выборе файлы загружаются в нашу систему.

Однако есть несколько отличий.

  • Они должны создать другую сущность, а это значит, что они попадают в другую конечную точку нашего API.
  • Текст кнопки другой.
  • Они принимают разные типы пантомимы.

Сначала мы создали компонент UploadButton для данных. Когда мы хотели реализовать UploadButton для словарей, мы столкнулись с тремя возможными шаблонами для повторного использования компонента:

Вариант 1. Используйте опору для установки типа

// In our Data page
<UploadButton type="data" />
// In our Dictionary page
<UploadButton type="dictionary" />

Таким образом, UploadButton очень легко использовать повторно. Однако реализация UploadButton не очень элегантна. Мы должны проверить опору type, чтобы использовать ту или иную вещь.

Наш UploadButton будет расти вместе с условными операторами, если мы добавим к нему функциональность. Также будет очень обременительно, если мы когда-нибудь захотим ввести новую сущность помимо данных и словаря.

Вариант 2. Передайте различия как реквизиты

// in our Data page Component
<UploadButton
  text="Upload data"
  acceptedValues={ this.props.dataAcceptedValues }
  handleUpload={ this.props.startDataUpload }
/>
// in our Dictionary page Component
<UploadButton
  text="Upload dictionary"
  acceptedValues={ this.props.dictionaryAcceptedValues }
  handleUpload={ this.props.startDictionaryUpload }
/>

Само по себе это выглядит хорошо. Однако, когда вы используете его в компоненте, который также имеет некоторые другие кнопки и компоненты, props этого компонента становится огромным списком. Делает компонент трудным для чтения и понимания.

Вариант 3. Создание новых компонентов

// in our Data page Component
<UploadDataButton />
// in our Dictionary page Component
<UploadDictionaryButton />

Это будет означать, что нам нужны два новых компонента: UploadDataButton и UploadDictionaryButton.

// in UploadDataButton
<UploadButton
  text="Upload data"
  acceptedValues={ this.props.dataAcceptedValues }
  handleUpload={ this.props.startDataUpload }
/>
// in UploadDictionaryButton
<UploadButton
  text="Upload dictionary"
  acceptedValues={ this.props.dictionaryAcceptedValues }
  handleUpload={ this.props.startDictionaryUpload }
/>

Создав их как отдельные компоненты, мы упростили их использование и повторное использование. Просто импортируйте это. Не нужно передавать prop. Мы можем сформулировать эту закономерность по следующему принципу:

Больше компонентов с меньшим количеством логики против меньшего количества компонентов с большей логикой

Если нам когда-нибудь понадобится добавить какую-то новую функцию, мы можем легко сделать это в автономном компоненте. Если функция, которую нам нужно добавить, является общей для обоих, у нас также будет UploadButton для нее.

Вывод

Этот шаблон принес нам несколько дополнительных функций:

  • Легко повторно использовать компоненты
  • Компоненты с меньшим количеством props
  • Гибкость для будущих функций

Обратной стороной является увеличение количества используемых компонентов с 1 до 3. В нашем случае это компромисс, на который мы готовы пойти.

Это простой сценарий, иллюстрирующий закономерность. Мы успешно применили его к более сложным ситуациям.

Нам нравится получать отзывы от сообщества, поэтому не стесняйтесь оставлять комментарии.

Спасибо за чтение!

Изначально опубликовано в Блоге Onedot.