Компоненты высшего порядка (HoC) в React
26 апреля 2022 г.Компоненты высшего порядка на самом деле являются шаблоном проектирования, основанным на композиционной природе React, который позволяет нам создавать компоненты на основе конкретных данных, которые мы хотим им передать.
Подумайте об этом так:
- Компоненты возвращают React Elements (JSX)
- Компоненты высшего порядка возвращают компоненты
Не запутайтесь — HOC сам по себе не является компонентом.
Помните: компоненты — это функции, которые возвращают элемент React (элемент JSX), компоненты более высокого порядка — это функции, которые возвращают эти компоненты.
На более высоком уровне абстракции HOC будет выглядеть примерно так:
```javascript
const withHOC = (Component, someData, otherArgs) => {
возврат (реквизит) => {
возврат (
<Компонент
customProp={someData.firstProp}
dataSomething={otherArgs.someOtherDataProp}
{...реквизит}
Можно также добавить вложенные элементы
with …
символизирует де-факто (наиболее часто используемое) соглашение об именах при работе с HOC.
И непрактичный пример того, как это можно использовать:
```javascript
импортировать с помощью Hoc из «предыдущий смысл»;
const Компонент = (реквизит) => {
возврат (
<дел>
Здравствуйте!
экспортировать по умолчанию с HOC(
Составная часть,
{ // Аргумент someData
prop1: 'что хорошего?',
prop2: { propProperty: 'содержащие некоторые данные'},
{ // аргумент otherArgs
arg1: {свойство: 'какое-то значение'}
Теперь, когда мы немного познакомились с этой концепцией, давайте рассмотрим более реалистичный сценарий, в котором вам могут понадобиться HOC.
Настройка проекта
Структура папки:
Вы можете проверить репозиторий здесь: https://github.com/Vlad-Mihet/React-HoCs для полной структуры файловой системы проекта.
Краткий обзор:
src/api
: будет содержать сохраненные сообщения в блоге с афферентным методом получения для поиска
src/components
: будет содержать общие компоненты; в нашем случае это будет BlogsContainer: он будет действовать как презентационный компонент и отображать только переданные ему записи блога.
src/views
: будет содержать представления приложения; в нашем случае это будет только представление «Главная», которое будет отображать список последних, популярных и архивных сообщений блога через компоненты контейнера в src/views/home/components.
src/views/home/components
: будет содержать компоненты, связанные с представлениемГлавная
; в нашем случае это будут все компоненты-контейнеры:ArchivedBlogs
,`PopularBlogs
иRecentBlogs
, которые будут нести ответственность за получение своих собственных данных.
src/App.js
: встраивает представлениеГлавная
Итак, в чем проблема с настройкой?
Что ж, у нас есть разные компоненты для довольно похожей задачи: инициализация части состояния для блогов, получение одного и того же реквизита blogs
, обновление состояния блогов во время монтирования и рендеринг с помощью одного и того же компонента BlogsContainer
.
Это дублирование кода, которое может быть решено путем реализации компонента более высокого порядка.
Решение
Создайте HOC withBlogs в разделе src/hocs со следующим содержимым:
```javascript
импортировать {useEffect, useState} из "реагировать";
const withBlogs = (Component, retrieveBlogs) => (реквизит) => {
const [блоги, setBlogs] = useState([]);
использоватьЭффект(() => {
установить блоги (получить блоги);
возврат (
<Блоги компонентов={блоги} {...реквизиты} />
экспорт по умолчанию с блогами;
HOC withBlogs получит компонент, а также метод извлечения блогов в качестве параметров, и ему будет поручено получить данные блогов и вернуть компонент с реквизитом blogs
в качестве извлеченных данных блогов.
Затем в представлении «Главная» мы можем отказаться от компонентов, которые мы использовали, из «src/views/home/components» и определить новые компоненты, созданные нашим новым HoC:
```javascript
импортировать React из «реагировать»
import {getArchivedBlogs, getPopularBlogs, getRecentBlogs} из '../api';
импортировать BlogsContainer из '../components/BlogsContainer';
импортировать withBlogs из '../hocs/withBlogs';
const RecentBlogs = withBlogs (BlogsContainer, getRecentBlogs);
const PopularBlogs = withBlogs (BlogsContainer, getPopularBlogs);
const ArchivedBlogs = withBlogs (BlogsContainer, getArchivedBlogs);
const Главная = () => {
возврат (
<раздел>
Последние блоги
<Недавние блоги />
<раздел>
Популярные блоги
<Популярные блоги />
<раздел>
Архив блогов
<Архивные блоги />
экспортировать домашнюю страницу по умолчанию;
Мы не только сократили дублирование кода, но и реализовали более простое и легко читаемое решение.
Теперь вам может быть интересно, почему бы нам просто не использовать компонент BlogsContainer
внутри HOC withBlogs, а не использовать общий параметризованный компонент?
Что, если мы когда-нибудь захотим сохранить ту же функциональность, но в другом корпусе? Например, у нас может быть компонент баннера, который извлекает блоги, но отображает их один за другим с вертикальной прокруткой?
В этом случае мы не будем передавать реквизиты для стилизации компонента BlogsContainer, а будем использовать другой компонент Banner.
Следует ли вам по-прежнему использовать HOC?
Смотря как. Использует ли проект, над которым вы работаете, компоненты на основе классов? Если да, то, скорее всего, вам придется использовать HOC, так как для них недоступны хуки. В противном случае я считаю, что хуки по-прежнему являются лучшим подходом к проблеме, которую мы рассмотрели.
Давайте посмотрим, как хуки решат нашу проблему:
Во-первых, нам нужно создать хуки useBlogs для обработки извлечения данных из блогов:
```javascript
импортировать {useState, useEffect} из «реагировать»;
const useBlogs = (getBlogs) => {
const [блоги, setBlogs] = useState([]);
использоватьЭффект(() => {
установитьБлоги(получитьБлоги());
вернуть [блоги, setBlogs];
экспортировать useBlogs по умолчанию;
Затем нам нужно будет обновить определения компонентов в представлении «Главная»:
```javascript
импортировать React из «реагировать»
import {getArchivedBlogs, getPopularBlogs, getRecentBlogs} из '../api';
импортировать BlogsContainer из '../components/BlogsContainer';
импортировать useBlogs из '../hooks/useBlogs';
const RecentBlogs = (реквизит) => {
const [блоги] = useBlogs (getRecentBlogs);
return
const PopularBlogs = (реквизит) => {
const [блоги] = useBlogs (getPopularBlogs);
return
const ArchivedBlogs = (реквизит) => {
const [блоги] = useBlogs (getArchivedBlogs);
return
const Главная = () => {
возврат (
<раздел>
Последние блоги
<Недавние блоги />
<раздел>
Популярные блоги
<Популярные блоги />
<раздел>
Архив блогов
<Архивные блоги />
экспортировать домашнюю страницу по умолчанию;
Благодаря подходу с хуками мы можем извлечь выгоду из гораздо более элегантной обработки композиционного аспекта React, не определяя шаблонный HOC, а скорее более удобный хук, и использовать его по мере необходимости, без необходимости проходить через несколько фабрик компонентов только для того, чтобы получить различный реквизит.
Это также позволяет нам лучше контролировать состояние, что является огромным плюсом в случае, если нам нужно выполнить более сложные вычисления состояния блога каждого компонента, такие как фильтрация или сортировка блогов.
Последнее слово
Я действительно считаю, что HOC чрезвычайно полезны для понимания, но если вы не работаете активно с компонентами класса, я настоятельно рекомендую вам изучить хуки, поскольку в целом с ними проще работать.
Я надеюсь, что вы узнали что-то новое, прочитав эту статью, и надеюсь, она вам понравилась. До встречи на следующем!
Ваше здоровье!
Если вам понравилась эта статья, вы также можете поддержать меня, купив мне кофе здесь.
Также опубликовано [здесь] (https://vlad-mihet.medium.com/what-are-higher-order-components-hocs-in-react-e299ff9bc96a)
Оригинал