Русский
Русский
English
Статистика
Реклама

Библиотека компонентов

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

26.12.2020 16:10:02 | Автор: admin

Меня зовут Ксюша Луговая. В СберКорусе я занимаюсь поддержкой библиотеки 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, // признак валидности компонента, есть только в onBlurname?: 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, и мы уверены, что не последний:)

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

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

Подробнее..

Taiga UI библиотека компонентов под Angular, которую вам стоит попробовать

12.01.2021 14:15:46 | Автор: admin

Привет!

Саша Инкин и я регулярно пишем на Хабр статьи по Angular. Почти все они основаны на нашем опыте разработки большой библиотеки компонентов.

Эту библиотеку мы развиваем, перерабатываем и дополняем уже несколько лет, а свои идеи проверяем на нескольких десятках проектов Тинькофф Бизнеса и внутренних систем компании. Мы рады сообщить: выложили нашу библиотеку в открытый доступ!

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

Как развивался наш UI Kit и как он организован

Если вам интересно узнать, зачем нам понадобилась отдельная библиотека компонентов и как она исторически развивалась, то сначала рекомендую прочитать крутейшую статью Юли Царевой Как организовать работу над библиотекой общих компонентов.

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

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

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

Эта часть обзавелась собственным дизайном и полной независимостью от контекста, а недавно оправдала свое название переездом в опенсорс. Давайте познакомимся с нашим UI Kit поближе!

Полностью модульный

Начнем с того, как организован проект. Taiga UI состоит из нескольких слоев, которые являются отдельными пакетами.

@taiga-ui/cdk

Фундаментальный пакет. Представляет собой набор директив, сервисов, токенов, абстрактных классов и утилит для абстрагирования и упрощения работы с Angular. Может быть использован как дополнительный мультитул с удобствами для вашего Angular-приложения любой сложности, а может и стать основой для построения собственного кита.

Пример сущностей:

  • TuiDestroyService для избавления от постоянного создания сабжектов destroy$ в компонентах.

  • TuiFilterPipe и TuiMapperPipe для обработки значений в шаблонах без лишних вызовов ChangeDetection.

  • Декоратор tuiPure для мемоизации значений геттеров и методов класса.

@taiga-ui/core

Пакет с базовыми компонентами для построения интерфейсов, а также с инструментами для основы веб-приложения. Это инструменты вроде рутового компонента, порталов для диалогов и выпадашек, настройки темизации и анимаций. Core задает вектор остальным пакетам c UI-элементами. На этом уровне появляется дизайн и все общие стили лежат тут.

@taiga-ui/kit

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

@taiga-ui/addon-*

Ряд тематических пакетов, которые основаны на первых трех. Например, есть пакет charts для графиков, commerce для работы с валютами, деньгами и вводом карт или даже отдельный пакет doc для построения собственной витрины аналогично нашей (ссылка на нее будет дальше).

Получается вот такая иерархия, при которой пакеты более высокого уровня строятся на базовых пакетах:

Вопрос: зачем тянуть в зависимости несколько пакетов, если я хочу лишь пару компонентов? Сколько они весят?

Несколько месяцев назад мы перешли от концепции единых точек входа в каждый пакет к полной разбивке всех пакетов на Secondary Entry Points. Чтобы сохранить удобный и привычный контракт импортов, мы устроили все пакеты по уникальной схеме, когда каждый последующий уровень вложенности является Secondary-поинтом к текущему, но Primary к сущностям своего содержимого.

Теперь все наши пакеты дают возможность импортировать сущности как из Primary точки входа, так и из любого уровня вложенности:

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

Такой подход к работе с Secondary Entry Points дает целый ряд плюсов в организации библиотек:

  • Бандл-приложений меньше, библиотека становится максимально tree shakable.

  • Любые циклические зависимости отлавливаются на этапе сборки.

  • Больше структурности в проекте, нет лишних связей между сущностями.

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

Кастомизируемый

Все стили и цвета задаются через CSS custom properties. Это позволяет легко собирать кастомные темы или даже подменять их в приложении на ходу.

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

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

Агностичный

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

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

Тем не менее мы контролируем базовый UX, чтобы вам не приходилось о нем думать: например, при фокусировке инпута с клавиатуры тултип покажет подсказку через секунду автоматически, чтобы screen reader прочитал ее:

Технологичный

Мы очень чтим девелоперские практики и стараемся придерживаться близкого к идеям самого фреймворка Angular-подхода.

Мы не боимся работать с DI, все наши компоненты в OnPush, а на всем проекте включен strict-режим TypeScriptа к типизации мы тоже относимся трепетно. Одним днем вы решите перейти на SSR, и наши компоненты в нем не сломаются.

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

Многообразный

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

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

Как начать использовать

Заходите на официальный сайт и в документацию библиотеки. Смотрите, изучайте и следуйте инструкциям:

taiga-ui.dev

Если вам хочется поддержать нас или было бы интересно понаблюдать за развитием библиотеки ставьте звездочку и подписывайтесь на Taiga UI в Github. Там можно задать любые вопросы, предложить идею или даже контрибьютить в код.

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

Хотите узнать больше?

В ближайший четверг, 14 января, мы проведем стрим на нашем новом Twich канале. Начнем в 19-00 по МСК.

Расскажем больше про проект, презентуем его структуру, основные части и особенности. Постараемся ответить на любые ваши вопросы про Taiga UI, Angular или разработку библиотек компонентов.

Не прощаемся

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

Поделитесь мнением о Taiga UI и расскажите, о каких компонентах, инструментах или процессах вам хотелось бы почитать в первую очередь?

Подробнее..

Упрощаем работу с Angular с помощью taiga-uicdk 5 наших лучших практик

11.05.2021 12:14:21 | Автор: admin

CDK базовый пакет библиотеки компонентов Taiga UI. Он не имеет никакой привязки к визуальной составляющей библиотеки, а скорее служит набором полезных инструментов для упрощения создания Angular-приложений.

Среди всех этих инструментов я выделил мою пятерку фаворитов. Я использую их во всех своих проектах и уже давно не представляю, как писать на Angular без них, потому что они ежедневно экономят мне массу времени.

Дисклеймер о весе библиотеки

Перед написанием статьи хотелось бы ответить на вопрос: Для чего тащить в бандл целый мультитул, когда мне нужна пара функций?

По результатам bundlephobia мы получим следующую картинку:

23 КБ результат не самый страшный, но и не очень приятный. Но все сущности наших библиотек лежат в отдельных Secondary Entry Point, что делает их полностью tree shakable. Это значит, что такой объем в бандле мы получим только в случае импорта и использования всех сущностей библиотеки в нашем приложении. Если вы импортите пару сущностей только они и попадут к вам в бандл, добавив к нему в результате меньше 1 КБ.

tuiPure продвинутая мемоизация вычислений

Это декоратор, который можно вешать на геттеры и чистые методы классов. Давайте разберем оба сценария.

Как геттер

Можно повесить декоратор tuiPure на геттер. В таком случае он позволяет сделать отложенные вычисления.

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

// template<div *ngIf="show">fibonacci(40) = {{ fibonacci40 }}</div>// component@tuiPureget fibonacci40(): number {  return calculateFibonacci(40);}

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

Пример 2. У нас есть компонент pull to refresh, который эмулирует поведение под iOS и Android. Один из его стримов вызывается только для Андроида, а для iOS нет. Завернем его в getter с pure, и ненужный Observable не будет создан для iOS.

<tui-mobile-ios-loader   *ngIf="isIOS; else angroidLoader"></tui-mobile-ios-loader><ng-template #angroidLoader>   <tui-mobile-android-loader       [style.transform]="loaderTransform$ | async"   ></tui-mobile-android-loader></ng-template>
@tuiPureget loaderTransform$(): Observable<string> {    return this.pulling$.pipe(        map(distance => translateY(Math.min(distance, ANDROID_MAX_DISTANCE))),    );}

Также можно обратиться к changes от ContentChild / ContentChildren: если мы вызываем такой геттер из шаблона, то уже можем быть уверены, что content готов. При соблюдении порядка также это можно провернуть и с ViewChild / ViewChildren.

Как метод

На метод тоже можно повесить декоратор @tuiPure. Тогда он будет работать следующим образом: при первом вызове метода посчитает значение и вернет его. Все последующие вызовы с теми же самыми аргументами будут возвращать уже посчитанный результат. Если аргумент изменится результат пересчитается.

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

get filteredItems(): readonly string[] {   return this.computeFilteredItems(this.items);}@tuiPureprivate computeFilteredItems(items: readonly string[]): readonly string[] {   return items.filter(someCondition);}

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

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

*tuiLet

Это простая структурная директива для объявления локальных переменных в шаблонах.

<ng-container *tuiLet="timer$ | async as time">   <p>Timer value: {{time}}</p>   <p>       It can be used many times:       <tui-badge [value]="time"></tui-badge>   </p>   <p>       It subsribed once and async pipe unsubsribes it after component destroy   </p></ng-container>

Вместо *tuiLetможно использовать *ngIf если вам не нужно показывать шаблон при falsy-значении (или если оно не предусмотрено). Но если вы работаете, например, с числами, то 0, скорее всего, является вполне адекватным значением. Тут и поможет *tuiLet

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

Метапайпы tuiMapper и tuiFilter

Мы создали пайп, чтобы не создавать другие пайпы, tuiMapper.

Он очень простой. Это pure-пайп, который принимает в себя чистую функцию для преобразования и произвольное количество аргументов к ней. В шаблоне это выглядит так:

{{value | tuiMapper : mapper : arg1 : arg2 }}

Также удобно и преобразовывать данные для инпутов компонентов в шаблоне или использовать через *ngIf / *tuiLet:

<div    *ngIf="item | tuiMapper : toMarkers : itemIsToday(item) : !!getItemRange(item) as markers"    class="dots">    <div class="dot" [tuiBackground]="markers[0]"></div>    <div        *ngIf="markers.length > 1"        class="dot"        [tuiBackground]="markers[1]"    ></div></div>

Добавление цветных маркеров-точек в календарях @taiga-ui/core

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

А еще у нас есть tuiFilter для удобства фильтрации массивов. Фактически это частный случай маппера, но нам нужен довольно часто. Поскольку это чистый пайп, то никаких проблем с производительностью из-за пересоздания массивов тут нет.

Документация на mapper / документация на filter

destroy$

Это Observable-based сервис, который упрощает процесс отписки в компонентах и директивах.

@Component({   // ...   providers: [TuiDestroyService],})export class TuiDestroyExample {   constructor(     @Inject(TuiDestroyService)      private readonly destroy$: Observable<void>   ) {}   //    subscribeSomething() {       fromEvent(this.element, 'click')           .pipe(takeUntil(this.destroy$))           .subscribe(() => {               console.log('click');           });   }}

Все что нам нужно добавить его в providers компонента и заинжектить в конструкторе. Я предпочитаю писать типы сущностей из DI, которые минимально необходимы в компоненте. Здесь это Observable<void>. Но можно писать и покороче:

constructor(private destroy$: TuiDestroyService) {}

Кстати, сервис в такой ситуации привязывается не к лайфсайклу компонента, а к его DI Injectorу. Это может помочь в ситуации, когда нужно подписаться в сервисе или внутри DI фабрики. Такие кейсы довольно редки, но зато TuiDestroyService в них буквально спасает например, когда мы хотели дергать markForCheck из фабрики токена в статье о DI фокусах для проброса данных.

Ссылка на документацию

Плагины ng-event-plugins

Фактически это внешняя библиотека ng-event-plugins, которая поставляется вместе с cdk (прямая зависимость, которую не нужно устанавливать отдельно). Она добавляет свои обработчики к менеджеру плагинов Angular. В ней есть несколько очень полезных плагинов, которые добавляют ряд возможностей в шаблоны компонентов.

Например, .stopи .preventпозволяют декларативно делать stopPropagation и preventDefault на любой прилетающий ивент.

Было:

<some-input (mousedown)="handle($event)">    Choose date</some-input>
export class SomeComponent {   //    handle(event: MouseEvent) {      event.preventDefault();      event.stopPropagation();      this.onMouseDown(event);   }}

Стало:

<some-input (mousedown.prevent.stop)="onMouseDown()">    Choose date</some-input>

Или модификатор .silent который позволяет не запускать проверку изменений на событие:

<div (mousemove.silent)="onMouseMove()">    Callbacks to mousemove will not trigger change detection</div>

Можно отслеживать ивенты в capture-фазе с помощью .capture:

<div (click.capture.stop)="onClick()">    <div (click)="never()">Clicks will be stopped before reaching this DIV</div></div>

Все это работает и с @HostListenerами, и с кастомными событиями. Вы можете почитать подробнее в документации ng-event-plugins.

Итого

Мы посмотрели ряд сущностей пакета @taiga-ui/cdk. Надеюсь, какие-нибудь из них вам приглянулись и тоже будут помогать во всех дальнейших проектах!

Кстати, у меня еще есть статья про саму библиотеку Taiga UI, в которой описаны остальные пакеты и общая философия библиотеки.

Подробнее..

Тупые и умные компоненты

21.09.2020 00:19:49 | Автор: admin

Меня зовут Илона, я Senior Experience Designer в EPAM. Работа для меня удачно совпадает с хобби в EPAM я проектирую интерфейсы для зарубежных заказчиков, читаю лекции для сотрудников и студентов лабы, менторю дизайнеров. В свободное время преподаю проектирование интерфейсов в магистратуре Университета ИТМО и веду Телеграм-канал о UX-дизайне.
В работе и преподавании я часто сталкиваюсь с проблемой: сложно организовать компоненты интерфейса так, чтобы было всегда понятно, какой компонент использовать, чтобы похожие компоненты не плодились и не путали дизайнеров и разработчиков.

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

Что вообще такое компоненты

Графический интерфейс (GUI), как правило, состоит из кнопок, полей, чекбоксов, текстовых блоков и пр. Именно это мы называемкомпоненты эдакая интерактивная (или нет) обёртка контента:кнопка Оформить заказ; чекбокс Я принимаю условия соглашения и т.д.

Для UX-дизайнера интерфейс в первую очередь инструмент решения пользовательских задач. Задача всегда существует в контексте: регистрация в контексте сайта авиакомпании, покупка в контексте интернет-магазина одежды. Поэтому дизайнеру очень важно использовать реальные заголовки, названия кнопок, пункты списков. Именно так мы иллюстрируем решение определённой задачи в определённом контексте.

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

Посмотрим на простом примере

Дизайним карточку товара в интернет-магазине: картинка, информация, цена и кнопка Купить.

А ещё требуется карточка товара для корзины. Там нет кнопки Купить, зато есть кнопка Удалить и селектор количества товара. Звучит как новый компонент. Делаем!

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

И вот у нас уже 3 компонента Карточка.

Карточки во всем своем многообразииКарточки во всем своем многообразии

Теперь мы хотим показать информацию о заказе в личном кабинете. Неплохо смотрелась бы Карточка!
Какую же из трёх использовать? Ни одна толком не подходит. Проще уже сделать новую.


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

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

Три группы правок в нескольких местах на макетах и в системеТри группы правок в нескольких местах на макетах и в системе

Изменений бы потребовалось в три раза меньше, если бы карточку переиспользовали.

Зачем и как переиспользовать компоненты

Переиспользование компонентов помогает:

  1. облегчить жизнь себе и разработчикам;

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

Во имя переиспользования, по примеру разработчиков React.js, делим компоненты на два типа:тупыеиумные.

Тупой компонент не привязан к бизнес-логике.Вместо контента в нём рыба, максимальное количество состояний и элементов. Универсальный кирпичик для конструктора интерфейса.
Если же тупой компонент размещается в контексте, на определённой странице, оснащается конкретным контентом и функциональностью он становится умным.

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

Шаблон карточки и примеры его примененияШаблон карточки и примеры его применения

Пример с карточками сделан в Figma. Тупая карточка Figma-component с применениемAuto Layout.Благодаря этому элементы карточки можно удалять и менять, а её размер подстроится под изменения. Умная карточка Figma-instance.

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

Скругление всех картинок одним движениемСкругление всех картинок одним движением

Тупой UI kit

Простая и понятная библиотека компонентов (UI kit), элементы которой легко переиспользовать и обновлять турбо-ускоритель дизайна и разработки. И состоит такая библиотека из тупых компонентов. Я называю её Тупой UI kit.
Если на вашем проекте уже есть UI kit, попробуйте сделать все компоненты в нём тупыми. Скорее всего, вы с удивлением обнаружите, что многие компоненты можно унифицировать: объединить похожие или удалить повторяющиеся. Отупить UI kit может быть непросто, понадобится время на ревизию системы и сильный дизайн-инструмент.Figmaотлично справляется, но иSketchне отстает.

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

Выводы

Разделяя компоненты на умные и не очень, вы:

  1. создаете унифицированный интерфейс;

  2. оптимизируете дизайн и разработку, не выдумывая новые компоненты без необходимости;

  3. оставляете возможность легко вносить изменения в дизайн и код;

  4. делаете поведение компонентов предсказуемым для пользователей.


Больше о проектировании интерфейсов и UX можно почитать в моём телеграм-канале Поясни за UX.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru