Meu nome é Ksyusha Lugovaya. Na SberCorus, estou apoiando a biblioteca de componentes Korus-UI React.
Cedo ou tarde, quase todo desenvolvedor enfrenta o problema de escolher uma biblioteca e, às vezes, a solução pode não ser trivial. Surgem questões: o que orientar na escolha de uma biblioteca, quais soluções populares o mercado oferece, quais são seus prós e contras? Avaliações e depoimentos nem sempre ajudam a encontrar uma solução.
No mundo do desenvolvimento, não existe um ajuste perfeito para todas as situações. Portanto, no artigo irei lhe dizer como resolvemos este problema, e analisarei com exemplos de análise de várias soluções populares como escolher uma biblioteca de componentes React para seu projeto.
Os principais critérios para a escolha de uma biblioteca
Cenários de uso da biblioteca. Isso parece óbvio, mas uma compreensão clara das tarefas é o principal critério de seleção.
Tipos de componentes de aplicativos. O tipo de aplicativo determina quais componentes você precisa. Freqüentemente, um conjunto de botões / caixas de seleção, campos de entrada básicos, listas / menus com estilos prontos são suficientes. Isso significa que você pode usar componentes simples com uma quantidade mínima de configurações e estilos prontos.
Personalização, formatação e interatividade no design. Se você precisa formatar e estilizar significativamente seus componentes, isso também é importante decidir com antecedência.
Quando os requisitos forem claramente declarados, responda às perguntas:
A documentação do projeto está bem escrita, existem exemplos interativos?
Quão ativamente o projeto é apoiado?
Quantos problemas existem no projeto e com que rapidez eles são resolvidos?
O projeto é gratuito ou licenciado comercialmente?
Os componentes são fáceis de personalizar?
O código da biblioteca é coberto por testes?
Quais navegadores e plataformas a biblioteca suporta?
Estas são perguntas universais para ajudá-lo a escolher uma biblioteca. Mesmo que a solução funcional seja ideal para as necessidades do seu projeto, a falta de suporte ou um grande número de bugs não resolvidos é um bom motivo para escolher outra biblioteca.
, :
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.
, .
:
-
css- ;
-
-
yandex-ui
. .
:
-
() ;
- yaml json. (css, json, js, ios, android) .
arui-feather ( )
. className, .
Korus-UI ()
LedaProvider. React .
. API- (. theme). .
. , , ( Loader ).
.
Material-UI
, 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
:
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 |
|
|
|
|
|
|
|
|
> 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, , :)
Também gostaria de expressar minha gratidão à equipe de desenvolvimento do SberCorus, o pai e inspirador ideológico da biblioteca, Artem Povolskikh . Se você estiver interessado em saber como o desenvolvimento de front-end funciona no SberCorus, leia o artigo de Artyom .
Compartilhe sua experiência com bibliotecas de componentes nos comentários. É interessante discutir quais vantagens e desvantagens você encontrou com a experiência pessoal e quais funcionalidades faltam no processo de trabalho.