Что выбрать в качестве библиотеки компонентов для React-проекта

Разработка веб-сайтовOpen sourceJavaScriptReactJSTypeScript
Из песочницы

Меня зовут Ксюша Луговая. В СберКорусе я занимаюсь поддержкой библиотеки React-компонентов Korus-UI.

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

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

Основные критерии выбора библиотеки

Сценарии использования библиотеки. Это звучит очевидно, но четкое понимание задач — первоочередный критерий выбора.

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

Настройки, форматирование и интерактивность в дизайне. Если вам нужно значительно отформатировать и стилизовать свои компоненты, это тоже важно решить заранее.

Когда требования четко сформулированы, ответьте на вопросы:

  • Хорошо ли составлена документация проекта, есть ли интерактивные примеры?

  • Насколько активно поддерживается проект?

  • Сколько в проекте issues и как быстро они решаются?

  • Проект бесплатный или коммерчески лицензированный?

  • Насколько легко настраиваются компоненты?

  • Покрыт ли код библиотеки тестами?

  • Какие браузеры и платформы поддерживает библиотека?

Это универсальные вопросы, которые помогут выбрать библиотеку. Даже если функционально решение идеально подходит под нужды вашего проекта, отсутствие поддержки или большое количество нерешенных багов — веская причина выбрать другую библиотеку.

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

  • Material-UI,

  • Semantic-UI-React,

  • yandex-ui,

  • arui-feather,

  • Korus-UI.

С одной стороны, в этом списке представлены наиболее популярные проекты – Material-UI и Semantic-UI-React, которые были созданы одним разработчиком и со временем обросли большим сообществом.

С другой стороны – библиотеки, созданные внутри крупных компаний (Яндекс, Альфа Банк) для своих проектов, которые постепенно обрели популярность в качестве opensource решений.

Далее рассмотрим сравнение библиотек в разрезе определенных выше критериев.

Компонентный состав

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

Компоненты библиотек можно разделить на несколько групп.

Layout-компоненты

Контейнеры, карточки, таблицы, гриды и прочие. Основные характеристики:

  • Отвечают только за отображение;

  • Часто принимают на вход только props.children;

  • Не имеют своего состояния и методов жизненного цикла;

  • Примеры: h1, section, div, span, Icon, Avatar.

Готовые дизайн-системы библиотек сильно упрощают верстку, если проекту не нужна своя тема стилей. Например, Material-UI и Semantic-UI могут вполне справиться с этой задачей. Однако в крупных коммерческих проектах своя дизайн-система и кастомизация стилей библиотек будет избыточной.

Компоненты-контролы (controls)

Кнопки, чекбоксы, радиокнопки, поля ввода, слайдеры — небольшие базовые компоненты, которые помогают «оживить» контент и обеспечивать взаимодействие с пользователем.

Основные характеристики:

  • Отвечают за отображение и не имеют внутреннего состояния;

  • Принимают данные и функции обратного вызова в качестве props;

  • Состояние компонентов связано в основном только с UI (disabled, required, isLoading).

Сложные модульные компоненты

Это группа компонентов с более сложной логикой, они расширяют функции базовых компонентов и могут их комбинировать.

Основные характеристики:

  • Имеют состояние;

  • Предоставляют данные и логику layout-компонентам (валидация, форматирование вывода, автодополнение);

  • Комбинируют другие компоненты.

Layout

Controls

Modules

Количество компонентов

Material-UI

App Bar, Avatars, Badges, Bottom Navigation, Divider, Grid List, Lists, Paper, Progress, Snackbar, Tables,

Button, Chip, Selection Controls, Text Fields, Pickers*

Dialog, Cards, Drawers, ExpansionPanel, Menu, Stepper, Tabs, Tooltip

26**

Semantic-UI-React

Container, Divider, Flag, Header, Icon, Image, Label, List, Loader, Placeholder, Rail, Reveal, Segment, Step, Breadcrumb, Form, Grid, Menu, Message, Table, Advertisement, Card, Comment, Feed, Item, Statistic

Button, Input, Checkbox, Radio, Select, Text Area

Accordion, Dimmer, Dropdown, Embed, Modal, Popup, Progress, Rating, Search, Sidebar, Sticky, Tab, Transition, Visibility, Confirm, Pagination, Portal, Ref, Transitionable Portal

52

yandex-ui

Badge, Divider, Icon, Image, Text, UserPic, ListTile, Spacer, Link, Spin

Attach, Button, Checkbox, Menu, Radiobox, RadioButton, Select, Slider, Textarea, Textinput, Tumbler

TabsMenu, Drawer, Dropdown, Messagebox, Modal, Popup, TabsPanes, Tooltip, Progress

30

arui-feather

Amount, CardImage, FlagIcon, Form, GridRow, GridCol, Heading, Icon, InputGroup, Label, Link, List, Paragraph, Spin

Attach, Button, CardInput, CheckBoxGroup, CheckBox, FormField, IconButton, Input, RadioGroup, Radio, Select, TagButton, Textarea, Toggle

CalendatInput, Calendar, Collapse, EmailInput, InputAutocomplete, IntlPhoneInput, Menu, MoneyInput, Notification, PhoneInput, Plate, Popup, ProgressBar, Sidebar, SlideDown, Tabs

44

Korus-UI

HTML tags factory***,

Currency, Tags

Button, Checkbox, Input, Radio, Rating, Slider, Switcher, Textarea

Autocomplete, ButtonGroup, Collapse, Collapsible,

DatePicker, DateRange, DateTimePicker, DateTimeRange, Dropdown, DropdownLink, DropdownSelect, Dropzone, FileDrop, FileUpload, Loader, MaskedInput, Modal, MultiSelect, Notifications, NumericRange, NumericTextBox, Pagination, Password, ProgressBar, StatusBar, StickyPanel, Tabs, TimePicker, TimeRange, Tooltip, Tour, Validation, VStepper, Wizard, form

45

+ Компоненты-обертки для всех основных HTML-тегов

*Material-UI использует нативный календарь браузера в компонентах с выбором даты

**Основные компоненты библиотеки, для которых есть примеры в документации

***Korus-UI создает обертку для всех основных HTML-тегов c единым API

Почти 50% компонентного состава Material-UI и Semantic-UI-React и около 30% в библиотеках yandex-ui и arui-feather — малофункциональные layout-компоненты. В Korus-UI более 70% — сложные модульные компоненты.

Кастомизируемость

Возможность подстраивать компоненты под собственный дизайн экономит много времени и сил в будущем. Сравним подходы к кастомизации визуального отображения компонентов на примерах.

Material-UI

  • С помощью MuiThemeProvider. Компонент использует контекст библиотеки React для передачи объекта с темой всем дочерним компонентам.

  • Через добавление классов. Все компоненты поддерживают атрибут className.

Для кастомизации дочерних компонентов необходимо воспользоваться атрибутом classes.

Библиотека заточена на применение CSS-in-Js, что может вызвать определенные трудности, если стили для приложения содержатся в CSS-файлах. Для внедрения кастомных стилей CSS-in-Js предоставляется HOC withStyles() либо хук makeStyles() для функциональных компонентов.

Semantic-UI-React

У Semantic-UI-React нет своей темы, можно использовать стили Semantic-UI.

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

Это:

yandex-ui

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

Возможности:

  • Создание кастомной темы с помощью инструмента themekit;

  • Переопределение значения (токены) в теме;

  • Дизайн-токены в формате yaml или json. Их можно собрать в итоговый файл (css, json, js, ios, android) и подключить к проекту.

arui-feather (Альфа Банк)

У библиотеки Альфа Банка нет руководства по кастомизации стилей в общедоступной документации. Компоненты поддерживают атрибут className, возможно задать кастомные классы только их оберткам.

Korus-UI (СберКорус)

  • Кастомизация темы с помощью компонента LedaProvider. Он использует контекст библиотеки React для передачи объекта с темой всем дочерним компонентам.

  • Можно написать кастомные стили под имеющуюся вёрстку. Полный список классов в компонентах находится в разделе API-документации (см. атрибут theme). Их можно переопределять глобально для всех компонентов одного типа или для каждого индивидуально.

Расширяемость

В работе с библиотекой может возникнуть потребность изменить внутренний элемент компонента. Например, добавить картинку или иконку в поле ввода, заменить элемент на новый (в компонент Loader передать кастомный элемент спиннера).

Рассмотрим решения.

Material-UI

Позволяет изменять корневые элементы с помощью атрибута component.

Например, компонент List по дефолту рендерит <ul> элемент. Его можно заменить другим элементом или React компонентом:

<List component="nav">
  <ListItem button>
    <ListItemText primary="Trash" />
  </ListItem>
  <ListItem button>
    <ListItemText primary="Spam" />
  </ListItem>
</List>

Semantic-UI

Semantic-UI-React компоненты поддерживают схожий по функциональности атрибут as:

<Button as='a' />

Переданный элемент или React-компонент заменяют корневой элемент. Все неподдерживаемые пропсы передаются корневому элементу в качестве атрибутов.

yandex-ui

Предлагает использовать библиотеку render-override. В ней есть набор хуков и компонентов для реализации переопределения элементов внутри составного компонента.

Пример:

import React from 'react'
import { useRenderOverride } from '@yandex/ui/lib/render-override'

const ElementOriginal = ({ children }) => <div>{children}</div>
const MyComponent = ({ renderElement }) => {
  const Element = useRenderOverride(ElementOriginal, renderElement)
  return (
    <>
      <Element />
    </>
  )
}

В библиотеке yandex-ui расширяемость для существующих компонентов не реализована.

arui-feather (Альфа Банк)

Расширяемость компонентов не реализована.

Korus-UI

Расширяемость внутренних элементов библиотеки с помощью специального API. На вход компоненту можно передать атрибут из названия элемента и суффикса Render. Атрибуту присваивается функция, возвращающая элемент, которым заменяют существующий.

Простейший пример:

labelRender={() => <MyCustomLabel />}

Структура метода позволяет вносить изменения максимально гибко:

({ Element, elementProps, componentProps, componentState }) => React.Node
  • Element - сам элемент

  • elementProps - props элемента

  • componentState, componentProps - для удобства дополнительно приходят объекты с props и state всего компонента

Если мы хотим, чтобы новый элемент принимал на вход те же пропсы, можно отредактировать пример:

<L.CheckBox
  labelRender={({ elementProps }) => <MyCustomLabel {…elementProps} />}
>
  Label
</L.CheckBox>

Типизация

Для типизации React-проектов применяются 2 основных инструмента:

  • Typescript

  • PropTypes

В документации React для большой кодовой базы отдается предпочтение Typescript. Это инструмент статической типизации, который позволяет отлавливать большинство ошибок еще до исполнения кода. У PropTypes проверка типизации осуществляется только после запуска кода — это существенный недостаток по сравнению с другими инструментами.

В основном рассматриваемые библиотеки для типизации используют Typescript. У Semantic-UI основная библиотека написана на ванильном JS, а Typescript используется только в Semantic-UI-React, созданной для интеграции с библиотекой React.

Покрытие тестами

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

Ради справедливости стоит отметить, что автоматические тесты — не панацея. Высокий процент покрытия не гарантирует качество теста и охват основных пользовательских сценариев.

Но без покрытия тестами невозможно проверить совместную работу компонентов (интеграционное тестирование) и их работу вообще (модульное тестирование).

Сравним библиотеки на покрытие тестами.

Инструменты

Типы тестов

% покрытия

Material-UI

Chai, Mocha, Sinon

Unit

95.28% Statements

87.22% Branches

97.51% Functions

95.26% Lines

Semantic-UI

Jasmine, Karma

Unit

Отчет о покрытии отсутствует

Semantic-UI-React

Chai, Enzyme

Unit

Отчет о покрытии отсутствует

yandex-ui

Jest, Enzyme

Unit

Запуск тестов приводит к ошибке

arui-feather

Jest, Enzyme

Unit

88.1% Statements

73.84% Branches

66.61% Functions

87.19% Lines

Korus-UI

Cypress, Jest

Unit, end-to-end

69.28% Statements

56.14% Branches

66.29% Functions

71.78% Lines

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

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

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

Наличие интерактивных примеров

Storybook

Material-UI

https://material-ui.com/ru/

-

-

Semantic-UI-React

https://react.semantic-ui.com/

+

-

yandex-ui

https://yastatic.net/s3/frontend/lego/storybook/index.html

-

+

arui-feather

https://digital.alfabank.ru/

+

-

Korus-UI

https://opensource.esphere.ru/korus-ui/

+

+

Поддержка

Иногда возникает проблема, которая требует сторонней помощи. Нужно заранее определить, как ее получить.

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

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

В разделе Pulse на GitHub можно ознакомиться со статистикой репозитория по количеству Pull Request и коммитов за определенный период времени. Он находится на вкладке Insights каждого репозитория. Рассмотрим статистику по выбранным библиотекам.

Material-UI

Semantic-UI

yandex-ui

arui-feather (Альфа Банк)

Korus-UI (СберКорус)

Популярность

Популярность библиотеки принято оценивать по звездам на GitHub и количеству скачиваний npm-пакета. Показатели легко проверить и измерить, они свидетельствуют о доверии разработчиков и наличии сообщества у библиотеки. Это упрощает ее использование и поиск решений для возникающих проблем.

Однако стоит помнить, что популярность — это также результат хорошей маркетинговой стратегии и SEO-оптимизации, которые могут обеспечить библиотеке первые места в выдаче поисковика. Поэтому следует изучить обсуждения в блогах и на форумах, например, на Stackoverflow, Medium, DEV. Обсуждения находятся в разделе issues проекта.

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

Звезды

Скачивания за последний год

Соотношение количества звезд и скачиваний за последний год, %

Material-UI

63 400

6 372 353

0,99

Semantic-UI

48 800

541 299

9

Semantic-UI-React

11 900

8 620 967

0,14

@yandex/ui

212

15 902

1,33

arui-feather (Альфа Банк)

559

26 744

2

Работа с формами и валидация данных

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

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

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

Сравним работу с формами в различных библиотеках на конкретном примере.

Задача: создать базовую форму авторизации с двумя полями для ввода логина и пароля и кнопкой отправки формы. Поля мы хотим сделать обязательными, чтобы незаполненное поле подсвечивалось, а текст ошибки отображался как при потере фокуса, так и после нажатия на кнопку «Отправить».

Korus-UI

Посмотреть код
const BasicForm = () => (
  <L.Div>
    <L.Input
      isRequired
      requiredMessage="Login is required"
      form="form"
      name="login"
      placeholder="Login"
    />
    <L.Input
      isRequired
      requiredMessage="Password is required"
      form="form"
      name="password"
      placeholder="Password"
    />
    <L.Button _warning form="form">
      Submit
    </L.Button>
  </L.Div>
);

Material-UI

Посмотреть код
const BasicForm = () => {
  const [login, setLogin] = React.useState("");
  const [loginError, setLoginError] = React.useState(false);
  const [password, setPassword] = React.useState("");
  const [passwordError, setPasswordError] = React.useState(false);

  return (
    <div>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          setLoginError(!login);
          setPasswordError(!password);
        }}
      >
        <p>
          <TextField
            error={loginError}
            placeholder="Login"
            value={login}
            onChange={(e) => {
              setLoginError(false);
              setLogin(e.target.value);
            }}
            onBlur={(e) => {
              setLoginError(!login);
            }}
            helperText={loginError && "Login is required"}
          />
        </p>
        <p>
          <TextField
            error={passwordError}
            placeholder="Password"
            value={password}
            onChange={(e) => {
              setPasswordError(false);
              setPassword(e.target.value);
            }}
            onBlur={(e) => {
              setPasswordError(!password);
            }}
            helperText={passwordError && "Password is required"}
          />
        </p>
        <Button type="submit" color="primary" variant="contained">
          Sign Up
        </Button>
      </form>
    </div>
  );
};

Semantic-UI-React

Посмотреть код
const BasicForm = () => {
  const [login, setLogin] = React.useState("");
  const [loginError, setLoginError] = React.useState(false);
  const [password, setPassword] = React.useState("");
  const [passwordError, setPasswordError] = React.useState(false);

  return (
    <div>
      <Form
        onSubmit={(e) => {
          e.preventDefault();
          setLoginError(!login);
          setPasswordError(!password);
        }}
      >
        <Form.Group>
          <Form.Input
            error={loginError && { content: "Login is required" }}
            placeholder="Login"
            name="login"
            value={login}
            onChange={(e) => {
              setLoginError(false);
              setLogin(e.target.value);
            }}
            onBlur={(e) => {
              setLoginError(!login);
            }}
          />
          <Form.Input
            error={passwordError && { content: "Password is required" }}
            placeholder="password"
            name="password"
            value={password}
            onChange={(e) => {
              setPasswordError(false);
              setPassword(e.target.value);
            }}
            onBlur={(e) => {
              setPasswordError(!password);
            }}
          />
          <Form.Button content="Submit" />
        </Form.Group>
      </Form>
    </div>
  );
};

arui-feather

Посмотреть код
const BasicForm = () => {
  const [login, setLogin] = React.useState("");
  const [loginError, setLoginError] = React.useState(false);
  const [password, setPassword] = React.useState("");
  const [passwordError, setPasswordError] = React.useState(false);

  return (
    <Form
      onSubmit={(e) => {
        e.preventDefault();
        setLoginError(!login);
        setPasswordError(!password);
      }}
    >
      <FormField>
        <Input
          error={loginError && "Login is required"}
          placeholder="Login"
          value={login}
          onChange={(value) => {
            setLoginError(false);
            setLogin(value);
          }}
          onBlur={(e) => {
            setLoginError(!login);
          }}
        />
      </FormField>
      <FormField>
        <Input
          error={passwordError && "Password is required"}
          placeholder="Password"
          value={password}
          onChange={(value) => {
            setPasswordError(false);
            setPassword(value);
          }}
          onBlur={(e) => {
            setPasswordError(!password);
          }}
        />
      </FormField>
      <FormField>
        <Button view="extra" type="submit">
          Submit
        </Button>
      </FormField>
    </Form>
  );
};

yandex-ui

Посмотреть код
const BasicForm = () => {
  const [login, setLogin] = React.useState("");
  const [loginError, setLoginError] = React.useState(false);
  const [password, setPassword] = React.useState("");
  const [passwordError, setPasswordError] = React.useState(false);

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        setLoginError(!login);
        setPasswordError(!password);
      }}
      className={cnTheme(theme)}
    >
      <Textinput
        error={loginError}
        placeholder="Login"
        value={login}
        onChange={(e) => {
          setLoginError(false);
          setLogin(e.target.value);
        }}
        onBlur={(e) => {
          setLoginError(!login);
        }}
        hint={loginError && "Login is required"}
      />
      <Textinput
        error={loginError}
        placeholder="Password"
        value={password}
        onChange={(e) => {
          setPasswordError(false);
          setPassword(e.target.value);
        }}
        onBlur={(e) => {
          setPasswordError(!login);
        }}
        hint={passwordError && "Password is required"}
      />
      <Button type="submit" view="action">
        Submit
      </Button>
    </form>
  );
};

Как видно из примеров, в Korus-UI задача создания формы с валидацией решается парой дополнительных атрибутов, тогда как в остальных библиотеках требуется достаточно много кода и проверок.

В Material-UI и yandex-ui нет компонента формы, в Semantic-UI-React и arui-feather компонент формы является простой оберткой тега <form> и не предоставляет никакой дополнительной функциональности.

Встроенная валидация полей отсутствует во всех рассмотренных библиотеках, кроме Korus-UI. Для реализации более сложной логики понадобится еще одна библиотека.

Сравнительный анализ библиотек React-компонентов

Подведем итог сравнительного анализа пяти библиотек React-компонентов.

Korus-UI (СберКорус)

Material-UI

Semantic-UI-React

arui-feather (Альфа Банк)

yandex-ui

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

Storybook

+

+

Примеры можно редактировать прямо в документации

+

+

+

Поддержка

Количество Pull Request за последний месяц

70

241

2

0

0

Лицензия

MIT license

MIT license

MIT license

Mozilla Public License 2.0

Mozilla Public License 2.0

Покрытие тестами

Процент покрытия > 50%

+

+

+

Не удалось выяснить

E2E тесты

+

Поддержка браузеров и платформ

Chrome

85.0.4183.121

>= 49

Last 2 v.

Last 2 v.

Last 2 v.

Firefox

81.0.1

>= 52

Last 2 v.

Last 2 v.

>= 23

Edge

85.0.564.44

>=14

12+

Last 2 v.

IE

11

11

11+

11+

11+

Safari

14

>= 10

Last 2 v.

Last 2 v.

Opera

Last 2 v.

>= 12.1

Yandex

Last 2 v.

?

Android

4.4+

5+

>= 4

iOS Safari

7+

Last 2 v.

>= 5.1

Кастомизируемость

Возможность подключения кастомной темы

+

+

+

+

Расширяемость

+

+

+

Типизация

Typescript

Typescript

Typescript

Typescript

Typescript

Популярность

Соотношение звезд на GitHub и количества скачиваний за последний год, %

0,99

0,14

2

1,33

Компонентный состав

Есть компонент для работы с формами

+

+

+

Наличие встроенной валидации

+

В этой таблице приведены только универсальные критерии для оценки качества инструментов. Кроме них, на выбор библиотеки значительно влияют субъективные факторы и конкретные требования проекта.

Далее я расскажу, на какие факторы ориентировались мы в СберКорусе, и как было принято решение о создании своей библиотеки.

Почему Korus-UI

Может возникнуть вопрос: зачем нужна еще одна библиотека? На рынке уже существует большое количество библиотек компонентов React на любой вкус.

Мы решили создать свою библиотеку, потому что ни одно из существующих решений не удовлетворяло нас полностью по компонентному составу, возможностям расширения и кастомизации. Не устраивали также возможности настройки форм и валидации данных — функции, которые нужны буквально в каждом проекте.

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

С учетом всех факторов в компании было принято решение создать свою библиотеку React-компонентов, которая упростила бы разработку фронтенда на всех будущих проектах. Кроме того, при большом количестве крупных заказов возникает острая необходимость в едином стеке технологий и универсальных инструментах для всех проектов. Ясно, что такие инструменты должны соответствовать высоким стандартам качества, предоставлять гибкие возможности по расширяемости и кастомизируемости.

На разработку библиотеки Korus-UI ушло 1,5 года. В процессе создания мы ориентировались на лучшие практики разработки opensource-библиотек.

Какие преимущества предоставляет Korus-UI

Формы и валидация

В Korus-UI подход к построению форм принципиально иной: поля и кнопка отправки формы связываются атрибутом form, в который передается строка с названием формы. Так элементы одной формы могут находиться в разных контейнерах, подключаться динамически, никакие общие обертки им не нужны. При этом создается объект формы, к которому можно получить доступ в обработчиках событий или с помощью метода L.form(). Есть возможность передать кнопке массив из названий форм, чтобы валидировать и отправлять несколько форм одним кликом.

У библиотеки Korus-UI удобный обработчик onValidationFail, который позволяет получить объект формы, не прошедшей валидацию. А еще есть приятный бонус — прокрутки к невалидным полям.

Валидация в Korus-UI — это отдельный компонент. Его основные фичи:

  • Валидация поля функцией или RegExp

  • Готовые валидаторы

  • Один или несколько валидаторов для каждого поля со своими сообщениями

  • Настраиваемые сообщения (текст и внешний вид)

  • Задание валидности поля извне через атрибут isValid

  • Валидация компонентов в состоянии unmounted

  • Валидация полей по потере фокуса, сабмите формы и по событию в приложении

  • Прокрутка к невалидным полям при сабмите формы

  • Валидация нескольких форм одной кнопкой

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

Единообразный API

Все компоненты поддерживают атрибуты, начинающиеся с нижнего подчеркивания _. Такие атрибуты будут преобразованы в имена css-классов:

<L.Div _flexBox> -> <div class="flex-box"></div>

Атрибут className также поддерживается.

В каждый компонент можно передать атрибут theme, который содержит набор css-классов для элементов компонента.

Все компоненты поддерживают атрибуты с суффиксом Render (см. раздел расширяемость).

Поведение и структура события расширены, соблюдается единый стандарт для всех компонентов:

{
  …Event, // оригинальное событие, сгенерированное React'ом
                
  // событие расширено объектом component, которое содержит данные из компонента
  component: {
    isValid?: boolean, // признак валидности компонента, есть только в onBlur
    name?: string, // имя формы, к которой привязан компонент
    value: any, // значение компонента
    … // другие свойства объекта (см. API компонента)
  }
}

Названия атрибутов с булевыми значениями начинаются с:

is: isOpen, isValid, isRequired, isDisabled

has: hasCloseButton

should: shouldCorrectValue

Все компоненты поддерживают атрибут ref.

Korus-UI расширяет механизм ref, принятый в React.

Недостатки Korus-UI

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

Еще можно отметить отсутствие поддержки мобильных платформ iOS и Android. Сейчас библиотека гарантирует поддержку только последних версий популярных браузеров. Подробная информация приведена в сравнительной таблице выше.

Итоги

Мы подробно рассмотрели основные критерии выбора библиотеки React-компонентов и проанализировали библиотеки Material-UI, Semantic-UI-React, arui-feather (Альфа Банк), yandex-ui, Korus-UI (СберКорус), опираясь на критерии качества.

Вот коротко то, что нужно учесть при выборе библиотеки:

  • Собственные нужды и требования

  • Кастомизируемость

  • Расширяемость

  • Типизацию

  • Покрытие тестами

  • Наличие техподдержки

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

  • Отзывы и активность сообщества библиотеки

С учетом всех требований мы разработали собственную библиотеку Korus-UI, которая имеет все шансы стать достойным конкурентом существующим на рынке инструментам. Библиотека активно развивается, количество проектов, использующих Korus-UI в компании постоянно растет.

В ближайшее время мы добавим новые компоненты. Также в планах расширение тестового покрытия, перевод на английский язык документации и актуализация Storybook.

Библиотека Korus-UI выложена в opensource и доступна на GitHub. Это первый шаг для нашей компании в opensource, и мы уверены, что не последний:)

Отдельно хочу выразить благодарность команде разработчиков СберКоруса, отцу и идейному вдохновителю библиотеки Артёму Повольских. Если вам интересно, как устроена фронтенд-разработка в СберКорусе, читайте статью Артёма.

Делитесь в комментариях своим опытом использования библиотек компонентов. Интересно обсудить, с какими преимуществами и недостатками вы сталкивались на личном опыте и какого функционала вам не хватает в процессе работы.

Теги:сберкорусразработка приложенийбиблиотека компонентовreactopensoursetypescriptjavascriptоптимизацияинструменты разработки
Хабы: Разработка веб-сайтов Open source JavaScript ReactJS TypeScript
+22
10k 61
Комментарии 34

Похожие публикации

Требуется JavaScript / React разработчик
от 50 000 ₽IT-AcesМожно удаленно
Middle | High middle front-end разработчик (React + Typescript)
от 80 000 до 160 000 ₽CSSSRМожно удаленно
Middle или Senior Frontend Developer (React)
от 200 000 ₽Ok.wikiМожно удаленно
Senior TypeScript разработчик
от 3 500 $GrabrМоскваМожно удаленно
TypeScript Frontend Developer (Vue.js)
от 150 000 ₽NetworkМоскваМожно удаленно

Лучшие публикации за сутки