Использование компонентов более высокого порядка в React для повторного использования и компоновки функций

Если вы когда-либо использовали декораторы в JS, вы легко поймете, как работает HOC. Вот отличная статья, посвященная основам декораторов:

https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841

Идея HOC в React очень похожа, поскольку она открывает возможность определять компоненты как набор повторно используемых функций.

Наиболее распространенным шаблоном является передача вашего HOC либо в контексте, либо в состоянии как свойства. Также очень часто можно увидеть, как HOC захватывает этот контекст или данные состояния из Redux или MobX.

Когда я узнаю, должен ли я сделать это таким образом?

Простой признак, на который следует обратить внимание, — понять, имеет ли смысл определение компонентов как композиции для ваших спецификаций.

Допустим, у вас есть 3 компонента, которые вы хотите определить: один — Apple, другой — Orange, а последний — недавно обнаруженный элемент AppleOrange.

Теперь один из способов сделать это, чтобы определить три компонента с полупохожим кодом:

import {Component} from 'react'
class A extends Component {/* apple code */}
class B extends Component {/* orange code */}
class C extends Component {/* apple and orange code */}

Это не СУХОЕ. Что произойдет, если вам понадобится AppleOrangeBlueberry? Все может просто выйти из-под контроля, и, прежде чем вы это узнаете, вы просто безумно копируете и вставляете.

Давайте сделаем резервную копию и посмотрим, сможем ли мы определить 2 HOC (Apple и Orange) и смешать их, чтобы получить все третьи:

@apple
class A extends Component {...}
@orange
class B extends Component {...}
@apple
@orange
class C extends Component {...}

Но эй, мы создаем веб-приложения, а не фруктовые лавки, поэтому давайте возьмем реальный пример магазина электронной коммерции:

@popup
class Promotion extends Component {...}
@wizard
class Signup extends Component {...}
@popup
@wizard
class Captcha extends Component {...}

Таким образом, «Промоакции» — это всплывающее окно, «Регистрация» — это мастер, а проверка капчи будет и тем, и другим.

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

На самом деле вы, вероятно, уже используете HOC в своем коде React, поскольку многие из наших любимых плагинов обычно используют этот шаблон:

@connect()
@reduxForm()
class ConnectedForm extends Component {...}

Подводные камни

Если ваш HOC делает слишком много, это может затруднить его последовательное использование в качестве миксина.

Мой совет — заставить ваш HOC делать только одну вещь. Чем более общая эта вещь, тем легче будет вписать ее в ваши различные приложения.

Обычно вы не хотите начинать писать что-то вроде этого:

@appleOrange //not that useful...?

или в реальной жизни

@popupWizard //not useful enough arguably

Последние мысли

Шаблон HOC отлично подходит для извлечения области управления состоянием React для существующего компонента и повторного использования этой бизнес-логики в других компонентах. На самом деле, если вы используете состояние в любом из ваших обычных компонентов, у вас может быть потенциальный HOC!

Другой способ представить шаблон HOC состоит в том, что он позволяет отделить бизнес-логику компонента от его логики представления. Когда вы разделяете свой компонент таким образом, вы фактически получаете HOC и компонент без состояния соответственно. Оказывается, эти два вкуса компонентов на самом деле вполне дополняют друг друга. Если ваша общая цель проектирования состоит в том, чтобы иметь в основном компоненты без состояния, вы также можете сосредоточиться на наличии большого количества HOC в смеси.

Мое мнение? Используйте HOC как можно чаще. Попробуйте извлечь их из всех компонентов ваших проектов. Если вы обнаружили, что написали код, который используется более чем в одном проекте, придумайте хорошее имя и отправьте его в npm 😃.

Вот некоторые HOC, которые я опубликовал сам:

Удачного миксина!