При разработке приложения на React совместное использование компонентов в разных приложениях и проектах наладить бывает не так-то просто. Здесь надо решить ряд задач:
- Необходимо убедиться, что компоненты хорошо документированы, чтобы другим разработчикам было проще понять, как их использовать.
- Необходимо визуализировать компонент, чтобы другие разработчики знали, как компонент выглядит в глазах пользователей.
- Необходимо отделить компонент от любых библиотек управления состоянием. Так будет обеспечен максимальный потенциал масштабирования.
Третий пункт особенно важен, потому что в React имеется коллекция сторонних библиотек управления состоянием, которые могут быть интегрированы с компонентом.
Например, когда в Facebook объявили о выпуске Recoil, ещё одной библиотеки управления состоянием для React, Дэн Абрамов (создатель Redux) написал в твиттере следующее: «Во-первых, Recoil используется только в нескольких местах. Facebook — это гигантская кодовая база с более чем 100 000 компонентами. Трудно ожидать, что везде будет применяться единый подход. Redux тоже используется в нескольких местах, но он не решает те задачи, которые пытается решить Recoil».
Когда у вас есть гигантская кодовая база (например, такая как у Facebook), неудивительно, что рабочие группы внутри компании прибегают к разным методам решения своих задач.
Одна группа будет использовать Redux, потому что эта библиотека хорошо подходит для их случая, в то время как другая предпочтёт для решения своей задачи Recoil. Третья вообще захочет задействовать MobX, оказавшуюся идеальным решением в их случае. Никогда не знаешь, какая новая технология будет использована вместе с компонентами в следующий раз.
И как же в таких динамично меняющихся условиях создать надёжную библиотеку компонентов, достаточно гибкую для работы с любыми другими библиотеками управления состоянием React?
Поначалу это может быть нелёгкой задачей. Но если приглядеться, то ключ к пониманию того, как сделать библиотеку повторно используемых компонентов, обязательно найдётся. И тут всё зависит от того, как к этой задаче подходить.
Обращайтесь с компонентом, как с NPM-пакетом
Как разработчику React вам должно быть известно, что новые библиотеки устанавливаются с помощью npm install
. Чтобы создать компоненты React для совместного использования, нужно начать обращаться к ними, как к теми самыми библиотеками, которые вы так часто устанавливаете.
Хороший NPM-пакет будет повторно использоваться во многих проектах с различными сценариями применения. Рассмотрим один такой пакет и попробуем понять, как делиться своим кодом и как делать это лучше.
Когда я пробовал React Spectrum, то обычно заглядывал в документацию его компонентов. Так, для создания совместно используемого компонента button
мне нужен был раздел документации Spectrum, посвящённый кнопке. Оттуда я узнал, что те или иные действия с кнопкой производятся с помощью соответствующих пропсов или свойств. Вот некоторые из этих свойств:
- Свойство
variant
влияет на визуальный стиль. - Свойство
children
определяет, каким будет текст кнопки. - Событие
onPress
аналогично событиюonClick
, хотя здесь больше нюансов:onPressStart
иonPressEnd
.
Одного этого компонента достаточно, чтобы прийти к выводу: хороший повторно используемый компонент предоставляет свои пропсы (свойства) в виде API. Внутри компонента могут находиться значения состояния, но разработчикам, использующим компонент, знать об этом ни к чему.
Основываясь на сделанном выводе, создадим компонент button
с гораздо более простым API. Вот пример:
import React from 'react';
import styled from 'styled-components';
import PropTypes from 'prop-types';const Button = styled.button`
cursor: pointer;
background: ${props => props.isPrimary ? "cornflowerblue" : "white"};
color: ${props => props.isPrimary ? "white" : "cornflowerblue"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid cornflowerblue;
border-radius: 3px;
`;
const StyledButton = ({
children,
onClick,
isPrimary
}) => (
<Button isPrimary={isPrimary} onClick={onClick}>{children}</Button>
)
StyledButton.propTypes = {
/**
* Содержимое кнопки или метка
*/
children: PropTypes.node.isRequired,
/**
* функция on click
*/
onClick: PropTypes.func.isRequired,
/**
* стиль: кнопка primary или нет
*/
isPrimary: PropTypes.bool,
};
StyledButton.propTypes = {
/**
* Содержимое кнопки или метка
*/
children: PropTypes.node.isRequired,
/**
* функция on click
*/
onClick: PropTypes.func.isRequired,
/**
* стиль: кнопка primary или нет
*/
isPrimary: PropTypes.bool,
};
StyledButton.defaultProps = {
isPrimary: true
};
export default StyledButton;
В этом компоненте button
задействована библиотека styled-components
для визуального стиля и имеется три свойства:
- Свойство
child
для текста кнопки. - Свойство
onClick
для выполнения функции при нажатии на кнопку. - Свойство
isPrimary
для изменения визуального стиля компонента.
Интерактивную демоверсию компонента смотрите здесь.
А теперь проверим, можно ли задействовать эту кнопку вместе с Redux. Оказывается, только что созданный компонент button
для совместного использования без проблем работает с Redux. Главное — отправлять данные о состоянии из хранилища Redux в свойства компонента, чтобы повлиять на то, что он выводит.
В следующем примере значение isPrimary
было сохранено в хранилище Redux и используется для работы с компонентом button
. При нажатой кнопке можно отправить dispatch
, чтобы переключить состояние с true
на false
:
function App() {
const isPrimary = useSelector((state) => state.isPrimary);
const dispatch = useDispatch();
const title = isPrimary ? "Primary" : "Secondary";
return (
<StyledButton
isPrimary={isPrimary}
onClick={() => {
dispatch({ type: "TOOGLE_BUTTON", payload: !isPrimary });
}}
>
{title}
</StyledButton>
);
}
export default App;
Для просмотра доступна интерактивная демоверсия.
А вот ещё один пример с реализацией MobX.
Естественно, нюансы реализации инструментов управления состоянием будут варьироваться от проекта к проекту. При создании компонентов React для совместного использования позаботьтесь о том, чтобы они чётко работали, а для этого должны предоставляться правильные свойства. Так вы сможете создавать несвязанные компоненты для задействования их во многих проектах и работы с различными сценариями применения.
Но всё это решает лишь третью задачу совместного использования компонентов React, а именно их отделение от любых инструментов управления состоянием. А ведь нужно ещё документировать, отслеживать, тестировать и визуализировать компоненты для создания надёжного рабочего процесса их совместного использования. И здесь на выручку приходит Bit.
Использование Bit как платформы библиотек компонентов
Приведённый чуть выше пример компонента button
даёт возможность предварительного просмотра содержимого созданного нами компонента, отображаемого в браузере. Можно даже отредактировать свойства в виртуальном редакторе, и изменения будут отображаться в интерактивном окне:
Это интерактивная среда в Bit для просмотра компонента в действии. А чуть ниже приведена документация по свойствам, доступным для этого компонента:
Документация генерируется автоматически при использовании PropTypes
внутри компонента.
Выглядит всё это впечатляюще, но что представляет собой этот Bit?
Bit — это платформа для совместной работы над компонентами, позволяющая использовать их в различных проектах и репозиториях. Это очень удобный инструмент, который производит регистрацию, тестирование, обновление и установку компонентов.
Заключение
Создание коллекции компонентов для повторного их задействования в большом количестве проектов и в различных сценариях применения — это большой вызов для любой команды разработчиков.
К счастью, хороший шаблон кода для совместного использования компонентов придумывать не нужно. Загляните в свои любимые библиотеки, почитайте документацию и просмотрите их исходный код. Возьмите за основу шаблон, который там найдёте, и создайте свой собственный.
Предоставляйте в компоненты свойства в виде API и как можно больше отделяйте компоненты от библиотек управления состоянием, чтобы в них не было никакой необходимости. Таким образом будет обеспечен максимальный потенциал масштабирования компонентов.
Прежде чем приступать к созданию библиотеки повторно используемых компонентов React, ознакомьтесь с руководством по повторно используемым компонентам Bit. Спасибо за внимание!
Читайте также:
- Что выбрать: React Native, Flutter или нативный подход
- React Query - залог эффективных запросов
- 5 Методов сохранения состояния в промежутках между перезагрузками страниц в React
Читайте нас в Telegram, VK и Дзен
Перевод статьи Nathan Sebhastian: Sharing React Components Between Different State Management Libraries