Представьте, что вы создали самое лучшее поле 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, позволяющий отдельно создавать, тестировать и предоставлять для обмена многоразовые компоненты, как строительные блоки проектов (атомы и молекулы), гарантирует, что каждый сможет применить их для разработки веб-приложений, готовых к бесконечному масштабированию.
Читайте также:
- Как создать приложение Todo на React
- Почему React 16 — это благословение для React разработчиков
- Что такое Редьюсеры: Как использовать их без Redux
Читайте нас в Telegram, VK и Дзен
Перевод статьи Prithwish Nath: Create Reusable React Components The Right Way