React tips for faster development at scale

от автора

Впервые я познакомился с React в 2015 году и вот уже использую его можно сказать повседневно 7 лет. Бесчисленное количество компонентов было написано за это время, React из подающей надежды модной технологии вырос в серьезную библиотеку и по сути стал стандартом для написания веб приложений в 2022 году.

Мы полюбили эту библиотеку за простое и лаконичное, но в тоже время очень мощное API, производительность, крутейшее коммюнити, наличия множество npm пакетов и просто за возможность решать прикладные задачи быстро и легко.


Скриншот официального сайта https://reactjs.org

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

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

Решил собрать несколько советов, которые за эти годы доказали свою эффективность и масштабируемость уже не в одном проекте.

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

Design system driven development

Да этот совет не совсем про React, а скорее про организацию разработки и взаимодействия с дизайнерами. Если у вас есть возможность инвестировать время в e2e дизайн систему от Figma/Sketch макетов до React компонентов, это действительно помогает экономить время при решении бизнес задач с развитием проекта.

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

Ссылочка тут.

Чтобы подытожить, тема 10/10 чем раньше на стадии жизненного цикла проекта начнете тем легче и лучше будет.

KISS

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

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

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

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

import React from 'react'  export default function UILibInputSelect(props) {   const {     dataTestID,     className,     children,     onClick,   } = props;    return (       <UILibInputSelect onClick= {onClick} dataTestID={dataTestID} className={className}>         {children}       </UILibInputSelect>   ); }  UILibInputSelect.useValue = useValue  const useValue = ({ initialItems }) => {     const [items, setItems] = React.useState(initialItems);      const getCheckedItems = (items) => items.filter(({ checked }) => checked);     const onChange = React.useCallback(         (id: string) => setItems(items.map(item => ({...item,checked: id === item.id}))),         [items],     );     const checkedItems = React.useMemo(() => getCheckedItems(items), [items]);     const onReset = React.useCallback(() => setItems(initialItems), [initialItems]);      return useMemo(         () => ({ items, onChange, onReset, checkedItems }),         [checkedItems, items, onChange, onReset,],     ); };

UI Agnostic components

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

К сожалению в Web разработке у нас такого нет, некоторые html теги вполне себе являются этой абстракцией, но к сожалению они более низкоуровневые и их не много.

Если вы меняли команды/проекты/компании работая во фронтоне последние лет 5 вы замечали, что приходя в новую команду, часто вам приходится создавать те же самые компоненты, как и в прошлой, только в новой теме. Так вот чтобы решить эту. Проблему и сэкономить время, можно использовать UI Agnostic или Headless компоненты.

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

Альтернативой тут могут служить уже готовые библиотеки компонентов вроде MUI, Bootstrap, AntDesign и многих других, но не все продуктовые команды будут готовы пожертвовать гибкость. Headless компоненты дают больше свободы разработчикам,, но и ответственности тоже становится больше.

Примеры библиотек куда посмотреть: HeadlessUI, BaseWeb и другие

Binary doesn’t scale

Component props в React это по сути маленький уровень API компонента, с которым другие разработчики будут взаимодействовать при его переиспользовании, по сути это одна из самых важных и ответственных частей в написании компонент. Так вот кроме упомянутого выше KISS, которого нужно придерживаться здесь еще один полезный совет, старайтесь избегать булевых флагов в интерфейсах если логически интерфейс пусть даже и не прямо сейчас, но в будущем может иметь третье и более значение, используйте Enum, String Union.

import React from 'react'   export default function UILibInputSelect(props) {   const {     variant,     dataTestID,     className,     children,     onClick,   } = props;      switch (variant) {         case UILibInputSelectVariant.small:             return (                 <UILibInputSelectSmall onClick= { onClick } dataTestID = { dataTestID } className = { className }>                     <UILibInputSelectSmallFlyout>                         {children}                     <UILibInputSelectSmallHint />                     </UILibInputSelectSmallFlyout>                 </UILibInputSelect>             );          default:          case UILibInputSelectVariant.default:             return (                 <UILibInputSelect onClick= { onClick } dataTestID = { dataTestID } className = { className } >                     { children }                     < /UILibInputSelect>             );     } }  UILibInputSelect.useValue = useValue UILibInputSelect.variant = UILibInputSelectVariant

React Component as Namespace

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

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

import React from 'react'   const App = () => {     return <div>         <UILibInputSelect variant={UILibInputSelect.variant.small} />     </div> }

CSS in JS

Если ваш проект вам позволяет, используйте css in js решения, они решают множество проблем классического css или css modules, а производительность их уже хороша. Самое популярное решение здесь это styled-components. У них непривычный синтаксис, но к этому привыкаешь и тебя перестает тоншить, а бенефиты остаются

Плюсы:

  • Возможность задешево передавать динамическое значение в стили без оверхед.
  • Типизация.
  • Dead Code Elimination.
  • Хорошо подходит для реализации дизайн систем.

Минусы:

  • Ниже производительность.
  • Синтаксис.
  • Не подходит для анимаций.

Строгая статическая типизация

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

Самым популярным выбором конечно же является Typescript. Быстрый, гибкий, хорошо интегрируемый с JS, React экосистемой и средами разработка, имеющий широкое признание в сообществе — отличный выбор.

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

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

Автоформатирование кода и линтинг

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

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

Используйте Prettier и ES/TS-lint в связке, они уже стали можно сказать стандартами для разработки.


ссылка на оригинал статьи https://habr.com/ru/post/694896/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *