⚛️ 6 самых важных шаблонов проектирования в React
Правильное использование паттернов проектирования – ключ к созданию надежных, эффективных и масштабируемых React-приложений. Рассказываем о шаблонах, которые стоит освоить в первую очередь.
При разработке приложений на React разработчики часто сталкиваются с повторяющимися задачами. Для решения этих задач были разработаны оптимальные практики – универсальные шаблоны проектирования, которые предлагают структурированный подход к:
- организации компонентов;
- управлению состоянием приложения;
- обработке данных.
Использование шаблонов улучшает производительность кода, облегчает поддержку и масштабирование проектов. В этой статье мы рассмотрим наиболее важные и распространенные шаблоны проектирования в React:
- Контейнер и презентация
- Компонент высшего порядка
- Составные компоненты
- Провайдер
- Редуктор состояния
- Компоновщик
Контейнер и презентация
Этот паттерн разделяет компоненты на две категории: контейнеры и презентационные компоненты:
- Контейнеры управляют данными и логикой состояния. Они загружают данные из внешних источников, при необходимости их обрабатывают и передают в компоненты презентации через пропсы. Контейнеры часто связаны с внешними сервисами, хранилищами Redux или контекстными провайдерами.
- Презентационные компоненты сосредоточены исключительно на отображении элементов интерфейса. Они получают данные от контейнеров через пропсы и визуализируют их в соответствии с HTML-разметкой и стилями CSS. Обычно это статические функциональные компоненты, которые проще тестировать и переиспользовать.
В качестве примера можно представить панель управления соцсетью, где пользователи просматривают посты друзей и взаимодействуют с ними. Вот как можно структурировать компоненты:
Контейнерный компонент FriendFeedContainer
отвечает за получение данных о постах друзей из API, выполнение любых манипуляций с этими данными и управление состоянием ленты новостей. Затем он передает данные в соответствующие презентационные компоненты.
Презентационный компонент FriendFeed
отвечает за отображение постов друзей на экране. Он получает данные о постах от своего родительского контейнерного компонента FriendFeedContainer
через пропсы.
Получив данные, FriendFeed
форматирует текст, добавляет изображения, аватары пользователей и любые другие визуальные составляющие постов. По сути, этот компонент не знает, откуда берутся данные, он просто их отображает в привлекательном виде.
Компонент высшего порядка
Компонент высшего порядка (HOC – Higher-Order Component) – это способ повторного использования логики компонентов в React. HOC представляет собой функцию, которая принимает компонент в качестве аргумента и возвращает новый компонент с дополнительной функциональностью.
Возьмем пример панели управления соцсетью, созданной с помощью хуков. Представим, что у нас есть несколько компонентов, которым нужно получать данные о пользователях из API. Вместо того чтобы дублировать код получения данных в каждом компоненте, можно создать HOC для получения данных и передачи их обернутым компонентам в качестве пропсов:
Этот паттерн позволяет повторно использовать логику получения данных во всех компонентах панели управления социальной сетью, не дублируя код:
- withUserData – компонент высшего порядка, который отвечает за получение пользовательских данных из API. Он оборачивает переданный компонент WrappedComponent и предоставляет ему полученные данные пользователя в качестве пропсов userData.
- UserProfile – функциональный компонент, который принимает пропсы userData и отображает информацию о профиле пользователя.
- UserProfileWithUserData – компонент, полученный путем обертывания UserProfile с помощью withUserData. Он наследует функциональность получения данных о пользователе от withUserData и отрисовывает профиль пользователя с помощью UserProfile.
- SocialMediaDashboard – основной компонент, в котором можно рендерить UserProfileWithUserData или любой другой компонент, которому нужны данные пользователя.
Хочу освоить современный стек и работать фронтенд-разработчиком. Что посоветуете?
Заглядывай на наш курс «Frontend Basic: принцип работы современного веба. С нуля до первого интернет-магазина» на котором ты освоишь HTML, CSS, JavaScript, React, Git. Курс состоит из 26 уроков и 28 домашних заданий. Наставник дает обратную связь. Для тех, кто хочет погрузиться в среду более углубленно, мы подготовили тариф с личным наставником.
Составные компоненты
Этот паттерн позволяет создавать компоненты, которые вместе формируют единый пользовательский интерфейс. При этом он обеспечивает четкое разделение ответственности и гибкость в настройке поведения и внешнего вида компонентов.
В этом шаблоне родительский компонент выступает контейнером для одного или нескольких дочерних компонентов, называемых составными компонентами. Эти дочерние компоненты взаимодействуют друг с другом для достижения определенной функциональности. Главная особенность составных компонентов заключается в том, что они совместно используют состояние и функциональность через свой родительский компонент. Такой подход упрощает разработку и помогает поддерживать чистоту кода.
Вот простой пример реализации паттерна составных компонентов в React с использованием хуков:
В этом примере:
- Toggle – родительский компонент, который объединяет составные компоненты ToggleButton и ToggleStatus.
- ToggleButton – дочерний компонент, отвечающий за отрисовку кнопки переключения.
- ToggleStatus – другой дочерний компонент, отвечающий за отображение состояния переключения.
- Компонент Toggle управляет состоянием
isOn
и предоставляет функциюtoggle
для его изменения. Он клонирует свои дочерние компоненты ToggleButton и ToggleStatus и передает им свое состояниеisOn
и функциюtoggle
в качестве пропсов.
Провайдер
Паттерн провайдер в React используется для управления и совместного использования состояния или данных приложения несколькими компонентами. Он подразумевает создание компонента-провайдера, который инкапсулирует состояние или данные и предоставляет их своим дочерним компонентам через контекст (context API). Такой подход позволяет обойтись без проброса пропсов и упрощает доступ к данным из любой части компонентного дерева.
Рассмотрим пример использования паттерна провайдера в React для управления данными пользователя во время авторизации:
В этом примере мы:
- Создаем контекст с названием UserContext при помощи функции
createContext
. Этот контекст будет использоваться для передачи данных пользователя и функций, связанных с авторизацией, между компонентами. - Определяем компонент UserProvider, который служит провайдером для UserContext. Этот компонент управляет состоянием пользователя с помощью хука
useState
и предоставляет методыlogin
иlogout
для обновления этого состояния. - Внутри UserProvider оборачиваем дочерние компоненты с помощью
UserContext.Provider
и передаем состояние пользователяuser
и функцииlogin
иlogout
в качестве значений. Теперь любой компонент, которому нужен доступ к данным пользователя или функциям, связанным с авторизацией, может использовать UserContext с помощью хука useContext.
Рассмотрим пример компонента, который получает данные пользователя из контекста:
В этом компоненте мы:
- Импортируем UserContext и используем хук useContext для доступа к данным пользователя
user
и функцииlogout
, предоставляемым UserProvider. - В зависимости от того, авторизован ли пользователь (
loggedIn
), отрисовываем разные элементы интерфейса. Например, если пользователь авторизован (loggedIn
имеет значениеtrue
), можно отобразить приветственное сообщение и кнопку выходаlogout
, а если не авторизован (loggedIn
имеет значениеfalse
), можно показать кнопку входа.
Редуктор состояния
Паттерн редуктор состояния – это контролируемый и предсказуемый способ управления состоянием React-приложения. Он использует функцию-редуктор для обработки изменений состояния и действий – точно так же, как это делают редукторы в Redux. Этот шаблон особенно полезен для управления сложной логикой состояния или состоянием, которое необходимо совместно использовать несколькими компонентами.
Рассмотрим пример реализации паттерна редуктора состояния для управления публикациями и уведомлениями пользователя в соцсети:
В этом примере мы:
- Определяем ADD_POST, DELETE_POST, ADD_NOTIFICATION, DELETE_NOTIFICATION – действия, которые можно выполнять с данными в панели управления аккаунта.
- Определяем функцию-редуктор
dashboardReducer
, которая принимает текущее состояние и действие, а затем возвращает новое состояние на основе этого действия. - С помощью хука useReducer создаем значение состояния
state
и функциюdispatch
для обновления состояния путем передачи действий редуктору. - Компонент Dashboard содержит логику для добавления и удаления постов и уведомлений. Он вызывает
dispatch
с определенными действиями, чтобы обновить состояние соответствующим образом. - В интерфейсе посты и уведомления отображаются как элементы списка с кнопками для их удаления. Пользователи могут добавлять новые посты или уведомления, нажимая соответствующие кнопки.
Как очевидно из этого примера, функция-редуктор централизует логику управления состоянием, делая ее более понятной и поддерживаемой.
Компоновщик
Идея компоновщика заключается в объединении мелких, многоразовых компонентов для создания более сложных компонентов или интерфейсов. Давайте проиллюстрируем этот паттерн на примере панели управления в соцсети.
Предположим, эта панель управления состоит из нескольких компонентов – UserInfo (информация о пользователе), Feed (лента новостей), Notifications (уведомления) и Sidebar (боковая панель). Можно объединить эти мелкие компоненты вместе, чтобы создать единый компонент панели управления. Такой компонент панели управления может выглядеть следующим образом:
В этом примере мы:
- Используем отдельные компоненты для UserInfo, Feed, Notifications и Sidebar. Каждый из них отвечает за отрисовку определенной части панели управления социальной сетью.
- Объединяем эти мелкие компоненты вместе в SocialMediaDashboard, чтобы создать весь интерфейс панели управления.
- Компонент App является точкой входа, где происходит передача данных (информации о пользователе, постов, уведомлений) в компонент SocialMediaDashboard.
Каждый компонент фокусируется на определенном аспекте интерфейса – такой код легко переиспользовать и поддерживать.
Другие полезные паттерны
Набор шаблонов, которые можно использовать при разработке React-приложений, не ограничивается перечисленными выше паттернами. Более полная коллекция паттернов представлена в репозитории книги React 18 Design Patterns and Best Practices, бесплатную версию которой можно скачать здесь.
При подготовке статьи использовалась публикация React Component Design Patterns.