Представьте, что вы создали самое лучшее поле FormField для рассылки новостей компании. Теперь вы приступаете к следующему заданию  —  помогаете другой команде с разработкой компонента React, который почти не отличается от того, что вы только завершили. Как же использовать компоненты несколько раз в разных приложениях и командах?

Вы можете удивиться: “Я уже написал код. Достаточно только скопировать его из репозитория”.

Но собираетесь ли вы копировать (внося коррективы) все необходимые зависимости, конфигурации и условные стили? А если у вас сотня компонентов в пяти разных репозиториях  —  и у всех них различные конвейеры обновления, за которыми нужно следить?

Одним из решений является монолитная библиотека: несколько компонентов публикуются в виде одного пакета, а в качестве зависимости используется “корневая” библиотека. Проблема в том, что монолиты не масштабируются. Все компоненты в пакете разом версионируются  —  вы не можете их комбинировать и варьировать.

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

Атомарный дизайн

Представьте, что можете хранить компоненты по отдельности в каком-нибудь репозитории и использовать их, когда они понадобятся вам или кому-то другому для другого проекта.

В этом и помогает Bit. Он предлагает следующие возможности.

  • Логически определять отдельные компоненты (или разбивать их на части до получения минимально возможных единиц, таких как пользовательский компонент Button).
  • Делать их независимыми от существующей библиотеки и контекста приложения.
  • Собирать, тестировать, версионировать и публиковать их как единый пакет на Bit, автоматически управляющий зависимостями.

Это и есть правильно выполненная компонентно-ориентированная разработка. Поскольку все компоненты становятся многоразовыми, их можно отдельно импортировать, обновлять и использовать для создания любого проекта  —  и все это с помощью npm install!

Начало работы

Возьмем практический пример. Простой компонент Input, созданный ранее, нужно использовать повторно и совместно в других проектах.

Посмотрим, как это сделать.

Шаг 1. Установка и запуск Bit

Прежде всего, установим Bit, а затем инициализируем рабочее пространство Bit Workspace в каталоге разрабатываемого проекта.

npx @teambit/bvm install
bit init

Данный сервер разработки позволяет создавать, импортировать, просматривать и изменять компоненты, а также управлять их зависимостями в одном месте. Это интуитивно понятный, наглядный способ компонентно-ориентированной разработки.

Шаг 2. Создание компонентов с помощью Bit

Приготовьтесь к кропотливой работе.

Команда bit create создает каталог компонентов.

bit create react input --scope exampleUser.exampleScope

Обратите внимание, что слово react стоит после bit create. Таким образом Bit получает команду создать компонент React. Доступны и другие шаблоны, например Node.js, MDX, React Hooks и так далее. Чтобы узнать о них больше, выполните команду bit templates.

Выясним значение аргумента scope. Bit scope  —  это репозиторий. Созданный на bit.cloud удаленный scope действует как пространство имен, позволяя экспортировать и хранить компоненты с тем же именем, что и компоненты, созданные другими пользователями/организациями, без конфликтов, и делая импорт гораздо более логичным.

Вы также можете установить свойство defaultScope в файле workspace.jsonc на [ваше имя пользователя на bit].[имя вашего scope], чтобы упростить команду bit create до bit create react input.

Выполнение команды bit create приведет к следующему результату:

1 component(s) were created
my-scope/input
location: my-scope/input
env: teambit.react/react (set by template)

Первый компонент готов.

Наряду с файлом, созданным для компонента input, было создано еще несколько файлов. Теперь каталог input выглядит так:

index.ts // корневой файл
input.docs.mdx // документация
input.tsx // компонент
input.composition.tsx // композиции
input.spec.tsx // тесты

Следующий шаг  —  добавление кода для ввода в файл input.tsx. Не будем тратить на это много времени  —  вы наверняка знаете, как создать поле ввода (input field).

Представим, что компонент input выглядит следующим образом:

export const Input = () => {
return <input className={styles.input} {...rest} />
};

Вы можете остановиться на данном этапе (тогда переходите к шагу 4). Но, вероятно, совместно и многократно используемый компонент без предварительного просмотра, документации и тестов не будет слишком полезным для кого-либо. Исправим это.

Шаг 3. Внесение корректив

  • Композиции

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

import React from "react";

import {Input} from "./Input";

export const BasicInput = () => <Input buttonText="Submit" />;

Теперь можно установить все зависимости и запустить UI рабочего пространства, чтобы посмотреть, как работает новый независимый компонент.

bit install && bit compile && bit start

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

  • Документация

Документация компонентов Bit написана в практичном формате MDX. Он позволяет встраивать JSX в разметку для визуально насыщенной и информативной документации.

input.docs.mdx:

---
description: An input element with a built-in button.

labels: ["input", "submit form"]
---

import { Input } from "./input";

### Изменение текста на кнопке

'''js live

<Input buttonText="Go" />

'''
  • Тесты

Даже идеальный дизайн компонентов подлежит тестированию. При использовании bit create автоматически создается файл *.spec.*. Однако Bit также распознает *.test.* как тестовый файл.

import React from "react";
import {screen, render} from "@testing-library/react";
import {BasicInput} from "./input.composition";

it("Renders the input", () => {
render(<BasicInput />);
const input = screen.getByRole("textbox");
expect(input).toBeInTheDocument();
});

it("Renders the button", () => {
render(<BasicInput />);
const button = screen.getByRole("button");
expect(button).toBeInTheDocument();
});

it("Renders the button text", () => {
render(<BasicInput />);
const button = screen.getByRole("button");
expect(button).toHaveTextContent("Submit");
});

Запустите тесты с помощью bit test.

PASS src/components/input/input.spec.tsx
✓ Renders the input (67 ms)
✓ Renders the button (19 ms)
✓ Renders the button text (12 ms)



Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 5.549 s
Ran all test suites.
test has been completed in 13.718 seconds.

Шаг 4. Версионирование и публикация

Выходим на финишную прямую. Осталось пометить компонент начальным номером версии и загрузить его в репозиторий.

bit tag -m “my first version”

Метки  —  это снепшоты. Когда компонент помечается, он проходит через процесс сборки в дополнение к блокировке текущего состояния исходных файлов. Затем компонент будет скомпилирован в распространяемый формат с упаковкой в файл .tar.

Как только компонент будет помечен, можно переходить к публикации!

bit login

bit export

Упакованный компонент будет экспортирован в удаленную область видимости (scope), определенную заранее, и сразу же доступен для импорта и использования в любом проекте React.

Шаг 5. Импорт Bit-компонентов

Первым делом примените выбранный вами пакетный менеджер для входа в Bit, используя свое имя пользователя, пароль и электронную почту (или аутентификацию на основе токенов, например Connect With GitHub  —  вход с помощью GitHub).

npm login --registry=https://node.bit.dev --scope=@bit

Затем просто выполните команду cd для перехода в каталог проекта, в котором хотите использовать импортированный компонент, и установите нужный компонент из репозитория Bit, как любую другую библиотеку.

npm i @exampleUser/exampleScope.input

Компонент (и его версия) теперь указан как зависимость в package.json. Можете использовать его в любом месте проекта React с помощью обычного оператора import.

import { useState, useEffect } from "react";
import { Input } from "@exampleUser/exampleScope.input";
import TodoRow from "./components/TodoRow/TodoRow";
import "./App.css";
function App() {
// здесь - хуки useState и useEffect для получения todo
// обработчики - здесь
return (
<div className="canvas">
<div className="todos">
{todos.map((todo) => (
<TodoRow
todo={todo}
handleCheck={handleCheck}
handleRemove={handleRemove}
/>
))}
</div>
<Input
buttonText="Submit"
handleChange={handleChange}
handleSubmit={handleSubmit}
/>
</div>
);
}
export default App;

Конечный результат: компонент Input импортирован, интегрирован и легко используется в простом приложении Todo.

Вывод

Вот и все! Теперь вы знаете, как разделить тесно связанные компоненты в проектах на независимые, чтобы хранить, а затем использовать их для компоновки чего угодно, где угодно и в любом контексте.

В этом суть атомарного дизайна. Инструментарий вроде Bit, позволяющий отдельно создавать, тестировать и предоставлять для обмена многоразовые компоненты, как строительные блоки проектов (атомы и молекулы), гарантирует, что каждый сможет применить их для разработки веб-приложений, готовых к бесконечному масштабированию.

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

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


Перевод статьи Prithwish Nath: Create Reusable React Components The Right Way

Предыдущая статьяKepler.gl — инструмент для визуализации геоданных на Python
Следующая статьяОт 0 до 300 SQL-запросов в месяц: 3 практических совета