При разработке приложения на 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

Это интерактивная среда в Bit для просмотра компонента в действии. А чуть ниже приведена документация по свойствам, доступным для этого компонента:

Документация по свойствам в Bit

Документация генерируется автоматически при использовании PropTypes внутри компонента.

Выглядит всё это впечатляюще, но что представляет собой этот Bit?

Bit —  это платформа для совместной работы над компонентами, позволяющая использовать их в различных проектах и репозиториях. Это очень удобный инструмент, который производит регистрацию, тестирование, обновление и установку компонентов.

Платформа Bit для совместной работы

Заключение

Создание коллекции компонентов для повторного их задействования в большом количестве проектов и в различных сценариях применения  —  это большой вызов для любой команды разработчиков.

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

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

Прежде чем приступать к созданию библиотеки повторно используемых компонентов React, ознакомьтесь с руководством по повторно используемым компонентам Bit. Спасибо за внимание!

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Nathan Sebhastian: Sharing React Components Between Different State Management Libraries

Предыдущая статьяМежорганизационный обмен данными
Следующая статьяJavaScript - идеальный выбор при аналитической обработке данных