Использование компонентов более высокого порядка в 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, которые я опубликовал сам:
Удачного миксина!