Понимаем компоненты высшего порядка в React на реальном примере

Stas Bagretsov
Mar 16 · 4 min read

В этой статье вы пошагово узнаете как создать компонент высшего порядка в React и как применять этот паттерн на реальном примере.

Перевод Understanding React Higher-Order Components by Example

В этом руководстве мы пройдемся по концепциям, которые необходимы для создания компонентов высшего порядка. Мы применим HOC, чтобы сохранить стэйт в localStorage, вызывая withStorage, с помощью которого мы сможем вставить функционал в другие компоненты без дублирования логики по всему приложению.

👉Мой Твиттер — там много из мира фронтенда, да и вообще поговорим🖖. Подписывайтесь, будет интересно: ) ✈️

Что такое компонент высшего порядка(HOC)

Компонент высшего порядка в React это паттерн, используемый для того, чтобы делить функционал между компонентами без повторения кода. Такие компоненты, по факту, не совсем являются компонентами, это скорее функции. Такая функция берёт компонент как аргумент и отдаёт компонент. Она переделывает компонент в другой компонент и добавляет дополнительные данные или фунционал. Вот вкратце:

const NewComponent = (BaseComponent) => {
// ... создает новый компонент, обновляя старый и отдавая результат
}

Подобная имплементация с которой вы возможно уже знакомы благодаря экосистеме React, это connect из Redux и withRouter и React Router. Функция connect из Redux используется, чтобы раздать компонентам доступ к глобальному стейту в Redux сторе и она передаёт значения компонентам в виде пропсов. Функция withRouter добавляет информацию о роутинге и функциональности в компонент, позволяя разработчику иметь доступ к роутеру с возможностью изменения роута.

Паттерн компонентов высшего порядка(HOC)

Такие компоненты это функции, которые берут компонент как аргумент и возвращают компонент. Это говорит о том, что HOC будет всегда иметь форму как тут:

Тут higherOrderComponent это функция, которая берёт компонент под названием WrappedComponent как аргумент. Мы создаём новый компонент под названием HOC, который отдаёт из рендера <WrappedComponent />. Пока тут нет никакого функционала, этот пример просто описывает общий партерн, которому должна следовать любая функция HOC. Мы можем вызвать HOC таким образом:

const SimpleHOC = higherOrderComponent(MyComponent);

Простой пример HOC

Теперь мы расширим наш компонент высшего порядка, чтобы добавить в него данные во вставленный компонент.

Наша команда выяснила, что магическим секретом является число 42. Некоторые из наших компонентов должны поделиться этой информацией и мы можем создать HOC под именем withSecretToLife, чтобы передать его как пропс нашим компонентам.

Обратите внимание, что этот пример практически идентичен первому. Всё, что мы сделали, так это просто проп secretToLife={42}, который позволил обернутому компоненту получить доступ к значению через this.props.secretToLife.

Ещё стоит обратить внимание, что используем оператор расширения на пропсах переданных компоненту. Так мы точно будем уверены в том, что любой пропс переданный обернутому компоненту будет доступен через this.props, так же, как и если бы мы вызывали этот компонент не через компонент высшего порядка.

Наш компонент WrappedComponent, который по сути является прокачанной версией <DisplayTheSecret/>, позволит нам получить доступ к SecretToLife как к пропсу.

Практический пример

Теперь у нас есть четкое понимание основ создания компонентов высшего порядка и мы можем сделать такой же, но реально имеющий практическое применение в реальном приложении. HOC имеет доступ ко всем дефолтным API Реакта, включая state и методы жизненного цикла.

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

На самом верху withStorage у нас один элемент в стейте компонента, который отслеживает доступность локального хранилища в браузере. Мы используем componentDidMount, который проверяет наличие localStorage в checkLocalStorageExists функции. Тут он будет тестировать сохранение элемента и ставить стейт на true, если процесс был успешным.

Мы также добавили три функции — load, save и remove. Они применяются для прямого доступа к localStorage API, в случае его доступности. Наши три функции в HOC передались обернутому компоненту, чтобы там уже они и отработали.

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

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

Внутри componentDidMount обернутого компонента мы сначала пытаемся получить доступ к username и favoriteMovie из localStorage. Если этих значений нет, то мы делаем API запрос this.props.reallyLongApiCall. Как только получаем ответ, то сохраняем данные в локальное хранилище и обновляем стейт компонента, чтобы вывести его на экран.

Соображения по поводу HOC

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

Не используйте HOC в рендере компонента. Получайте доступ к HOC только за пределами определения компонента.

Статичные методы должны быть скопированы, чтобы к ним оставался доступ. Очень простой способ сделать это — использовать hoist-non-react-statics пакет.

Ref‘сы не передаются.

Stas Bagretsov

Written by

Надеюсь верую вовеки не придет ко мне позорное благоразумие. webdev/sports/books

More From Medium

Related reads

2.8K

Related reads

Related reads

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade