Головна / Статті

Створення налаштовуваного компонента вибору для React Native Paper

Покрокове керівництво з проектування та оприлюднення коду react-native-paper-select у відкритому доступі, яке охоплює функції пошуку, багатократний вибір елементів, розділені списки та компроміси щодо продуктивності.

Видавець: REACTAPP.TOP12 хв читання2663 слів

Джерела: I Built a React Native Select Component — and Turned It Into an Open-Source Package: `react-native-paper-select`

Створення справжнього спадного меню в React Native майже ніколи не є настільки простим, як здається

Якщо ви витратили час на спробу реалізувати належне спадне меню в React Native, ви вже знаєте, що «просто спадне меню» швидко перетворюється на набагато складніше завдання.

Вам доводиться керувати станом вибору, підключати функції пошуку, підтримувати багатократний вибір, працювати з довгими списками, формувати інтерфейс у спосіб, який здається природним для мобільних пристроїв, додавати перевірки та стежити за тим, щоб все це візуально гармоніювало з рештою вашого додатку.

Якщо ваш проєкт вже побудований на основі React Native Paper, використання окремої бібліотеки інтерфейсу лише для створення функціонального поля вибору здається зайвим.

Саме ця невідповідність є проблемою, яку було створено для вирішення цей компонент.

Метою був повторно використовуваний компонент вибору, який би гармонійно вписувався у React Native Paper, підтримував як одиночний, так і багатократний вибір, та дозволяв уникнути необхідності постійного повторного створення однакових шаблонів взаємодії у кожному проекті.

Тож його було створено з нуля.

Те, що спочатку було досить вузькоспрямованим компонентом інтерфейсу, з часом перетворилося на react-native-paper-select — багатофункціональний пакет для React Native з відкритим кодом, який тепер включає функції пошуку, багатократного вибору, відображення даних у форматі чіпів, розділених списків, вибору за допомогою кнопок-радіо, нижніх панелей, меню та ефективного відображення списків.

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

Проблема

На перший погляд, списки випадання здаються простими.

Однак як тільки ви починаєте їх реалізовувати, з’являється довгий список дизайнерських питань:

  • Як відображати поточне обране значення?
  • Чи потрібно, щоб поле підтримувало один вибір чи кілька?
  • Який правильний формат для списку варіантів?
  • Як має працювати пошук у цьому списку?
  • Чи має поведінка відрізнятися між Android та iOS?
  • Як відображати дуже довгі списки, не погіршуючи продуктивність?
  • Як зробити API для розробників простим?
  • Як дозволити налаштування, не перетворюючи компонент на щось складне у використанні?

Розв’язувати ці питання з нуля в кожному окремому додатку не мало сенсу.

Замість створення ще одного унікального компонента, призначеного конкретно для додатку, було доцільніше з самого початку розробити щось, що можна буде використовувати знову.

Основна ідея була простою:

Створити компонент для вибору на основі власних UI-елементів React Native Paper та зробити його настільки зручним, щоб інші розробники React Native справді захотіли ним скористатися.

Представляємо react-native-paper-select

react-native-paper-select — це налаштовуваний компонент для React Native, який підтримує як ситуації однократного, так і багатократного вибору.

У першій версії використовувалися вже наявні у React Native Paper елементи, зокрема:

  • TextInput
  • Checkbox
  • Dialog

Метою було надати розробникам можливість вибору, яка б візуально та функціонально відповідала додаткам, вже створеним за допомогою системи дизайну React Native Paper.

У міру розвитку пакету він вийшов за межі початкової реалізації, щоб підтримувати додаткові стилі візуалізації та більш розширену логіку вибору.

Встановлення пакета

Щоб почати працювати, потрібно лише кілька кроків.

npm install react-native-paper-select

Або, якщо ви віддаєте перевагу Yarn:

yarn add react-native-paper-select

Після встановлення імпортуйте компонент ось так:

import { PaperSelect } from 'react-native-paper-select';

Базовий Select

Щоб створити мінімальне поле вибору, вам потрібен лише список опцій та функція для обробки вибору.

Ось приклад:

const [selected, setSelected] = useState({
  value: '',
  label: '',
});
const options = [
  {
    _id: '1',
    value: 'React Native',
  },
  {
    _id: '2',
    value: 'Flutter',
  },
  {
    _id: '3',
    value: 'Native Android',
  },
];

А потім відобразіть компонент:

<PaperSelect
  label="Framework"
  value={selected.label}
  onSelection={(value) => setSelected(value)}
  arrayList={options}
  selectedArrayList={selected}
/>

Тут важливо не те, наскільки мало коду потрібно.

Важливо те, що приховує цей код.

З точки зору додатку насправді існує лише два запитання, які потрібно відповісти:

Які опції доступні?

та

Що обрав користувач?

Усе, що стосується візуалізації та взаємодії, обробляється безпосередньо самим компонентом.

Вибір одного елемента проти вибору кількох

Підтримка як вибору одного елемента, так і вибору кількох з самого початку була однією з ключових вимог до цього компонента.

Механізм вибору одного елемента досить простий у розумінні:

Select Framework
----------------
○ React Native
○ Flutter
○ Native Android

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

Select Technologies
-------------------
☑ React Native
☑ TypeScript
☐ Flutter
☑ Node.js

Це означає, що компонент мусить піклуватися про:

  1. Відстеження стану вибору
  2. Обробку скасування вибору
  3. Відображення кількох обраних значень одночасно
  4. Повернення оновленого набору обраних елементів
  • Підтримка синхронності відображуваного інтерфейсу користувача з базовими даними
  • Метою було утримати всю цю складність всередині самого компонента, а не перекладати її на кожного розробника, який використовує пакет.

    Чому React Native Paper?

    Оскільки основне додатку вже базувалося на React Native Paper, створення компонента select на основі цієї ж системи дизайну було логічним вибором.

    Замість того, щоб заново створювати кожен візуальний елемент, компонент міг повторно використовувати елементи інтерфейсу, які вже надавав Paper.

    На високому рівні внутрішня структура виглядала приблизно так:

                    PaperSelect
                         │
              ┌──────────┴──────────┐
              │                     │
          TextInput            Selection UI
                                    │
                        ┌───────────┼───────────┐
                        │           │           │
                     Checkbox      Radio       List
    

    Цей вибір дизайну приносить реальну користь.

    Будь-який додаток, який вже використовує React Native Paper, може додати цей компонент select без впровадження візуального стилю, який би конфліктував з рештою інтерфейсу.

    Найраніша версія цього компонента пропонувала лише діалогове вікно для вибору.

    Інтеракція працювала так:

    TextInput
        ↓
    User taps field
        ↓
    Dialog opens
        ↓
    User selects an item
        ↓
    Selected value appears in TextInput
    

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

    Вимоги до користувацького інтерфейсу сильно відрізняються в різних додатках.

    Щоб врахувати це, компонент було розширено для підтримки кількох способів відображення:

    • Діалогове вікно
    • Нижній листок
    • Меню

    Завдяки цій зміні один і той самий компонент вибору можна використовувати у дуже різних контекстах інтеракції, і розробникам не доводиться переписувати свою інтеграцію для перемикання між ними.

    Наприклад:

    <PaperSelect
      presentationStyle="bottomSheet"
      ...
    />
    

    Ця гнучкість стала значним кроком уперед для бібліотеки.

    Логіка вибору залишається ідентичною незалежно від обраного стилю — змінюється лише спосіб її відображення користувачеві.

    Робота з великими списками

    Не такою очевидною проблемою у компонентах у форматі спадного списку є як ефективно працює список у міру його збільшення.

    10 items
    

    Це дуже просто для відображення.

    Тепер уявіть собі компонент з:

    1,000 items
    

    або навіть:

    10,000 items
    

    Відображення стількох елементів списку одночасно може почати погіршувати швидкість реакції мобільного додатку.

    Щоб уникнути цього, пакет використовує FlashList для відображення своїх списків опцій.

    Концепція є простою:

    Large dataset
          ↓
    Virtualized list
          ↓
    Render what is needed
          ↓
    Better scrolling performance
    

    Продуктивність — це проблема, яку не можна відкладати до моменту створення чогось масштабного.

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

    Пошук

    Чим більше варіантів для вибору, тим важливішим стає пошук.

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

    Потік дій виглядає так:

    Search
      ↓
    Filter options
      ↓
    Select result
      ↓
    Update selection
    

    З точки зору користувача це може здатися незначним доповненням, але воно суттєво впливає на зручність використання, коли обсяг даних перевищує кілька елементів.

    Багатовибірковий режим з іконками

    Відображення кількох обраних значень одночасно швидко призводить до зайвої заплутаності.

    Наприклад, значення на кшталт:

    React Native, TypeScript, Node.js, MongoDB
    

    важко розпізнати, якщо його помістити у стандартне поле введення тексту.

    Іконки вирішують цю проблему.

    Вибрані значення можна також відображати як окремі, чітко визначені блоки:

    [ React Native ] [ TypeScript ]
    [ Node.js ]      [ MongoDB ]
    

    Цей компонент підтримує такий дисплей на основі чипів у сценаріях багатовибору, що дає користувачам набагато чіткіше уявлення про те, що вони обрали.

    Це також робить видалення окремих виборів набагато інтуїтивнішим.

    Роздільні списки

    Ще однією вимогою була можливість групувати пов’язані опції разом.

    Замість одного довгого, рівного списку на кшталт:

    React
    Angular
    Vue
    Node.js
    Java
    Python
    MongoDB
    PostgreSQL
    

    опції можна організувати під заголовками:

    Frontend
    
    ☐ React
    ☐ Angular
    ☐ Vue
    Backend☐ Node.js
    ☐ Java
    ☐ Python
    Database☐ MongoDB
    ☐ PostgreSQL
    

    Таке групування значно полегшує огляд та розуміння великих наборів опцій.

    У режимі багатовибору можливість обирати цілу секцію одночасно значно прискорює процес.

    Наприклад:

    ☑ Frontend
    
        ☑ React
        ☑ Angular
        ☑ Vue
    

    Це краще, ніж змушувати користувача торкатися кожного елемента по черзі.

    Полічки для одиночного вибору

    Полізначки є доцільними, коли можна вибрати більше одного варіанта.

    Але у сценаріях одиночного вибору полічки чіткіше доносять намір до користувача.

    Саме тому пакет також пропонує варіант інтерфейсу вибору у вигляді полічок.

    Основна ідея залишається незмінною:

    Options
       ↓
    User chooses one
       ↓
    Selection state updated
    

    Змінюється лише візуальне представлення.

    Це підкреслює важливий принцип створення повторно використовуваних компонентів:

    Тримайте логіку вибору окремо від способу її візуального відображення.

    TypeScript та проектування API

    Оскільки цей інструмент призначений для використання іншими розробниками, форма API має таке ж значення, як і вигляд інтерфейсу.

    Той, хто використовує пакет, не повинен знати нічого про його внутрішню роботу.

    Ідеально, якщо вони можуть міркувати щодо цього виключно з точки зору:

    Input
      ↓
    Options
      ↓
    User interaction
      ↓
    Selection
      ↓
    Callback
    

    замість:

    Dialog state
    Modal state
    List state
    Search state
    Checkbox state
    Rendering state
    ...
    

    Добре спроєктований API компонента приховує цю внутрішню складність від користувача.

    Це один із найясніших уроків, отриманих під час створення та вдосконалення цього пакету.

    Опен-сорс змінює спосіб розробки

    Написання компонента для власного додатку — це інше завдання, ніж написання його для ширшої аудиторії розробників.

    У межах одного додатку вимоги можуть бути такими:

    "Це вирішує мою конкретну проблему."

    Коли продукт стає опен-сорсом, питання змінюється на:

    "Чи буде цей API зрозумілим розробнику, який ніколи не бачив вихідного коду?"

    Ця зміна впливає на ваші пріоритети під час розробки.

    Раптово ви починаєте приділяти набагато більше уваги таким речам:

    • Цілісність API
    • Документація
    • Зворотна сумісність
    • Крайні випадки
    • Розумні значення за замовчуванням
    • Визначення типів
    • Опції налаштування
    • Продуктивність
    • Версіонування

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

    Як проект розвивався з часом

    Те, що починалося як простий компонент вибору, поступово перетворилося на більш повний набір інструментів для вибору.

    Його розвиток можна приблизно описати так:

    Simple Select
          ↓
    Single Selection
          ↓
    Multi Selection
          ↓
        Search
          ↓
    Large List Handling
          ↓
        Chips
          ↓
       Sections
          ↓
    Radio Selection
          ↓
    Bottom Sheet
          ↓
    Menu Presentation
    

    Кожна нова функція вирішувала реальну проблему, пов’язану з користувацькістю чи досвідом розробника.

    Це один із аспектів розробки відкритих продуктів, який виділяється.

    Коли ви розсилаєте версію 1, у вас рідко є чітке уявлення про те, як буде виглядати готова бібліотека у кінцевому підсумку.

    Натомість структура пакету постійно змінюється у міру виникнення реальних вимог, відгуків користувачів та нових сценаріїв використання.

    Уроки з цього процесу

    1. Незначні проблеми можуть перетворитися на корисні проекти з відкритим кодом

    Початкова проблема жодним чином не була революційною.

    Просто бракувало компонента select, який можна було б використовувати знову.

    Але існує справжня різниця між тим, щоб виправити щось для власних потреб, та тим, щоб довести його до рівня, коли інші люди також зможуть його взяти та використовувати.

    Іноді ця різниця є достатньо великою, щоб обґрунтувати створення проекту з відкритим кодом.

    2. Щоб щось стало відновлюваним, потрібно належним чином абстрагувати його

    Добре спроєктований компонент не повинен бути прив’язаним до конкретного додатку, який його створив.

    Натомість він має мати чистий, простий інтерфейс ззовні, приховуючи свою внутрішню складність.

    Цей принцип застосовується не лише у світі React Native.

    3. Дизайн компонентів також стосується користувацького досвіду

    Робити компонент пере використовуваним на рівні коду — це не все.

    Не менш важливим є те, які враження справляє взаємодія з ним.

    Діалогові вікна, нижні панелі, меню, іконки, поля пошуку, кнопки вибору та розділені списки — це просто різні варіанти відповіді на одне основне питання:

    Який найкращий спосіб дозволити користувачеві зробити вибір?

    4. Пере використовувані компоненти мають будуватися з урахуванням продуктивності

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

    Саме тому рішення щодо відображення списків та віртуалізації мають прийматися на етапі проектування, а не як пізніше доповнення, коли у продакшені починають з’являтися проблеми з продуктивністю.

    5. Документація є основною частиною пакету, а не додатком

    Одного лише працездатного коду недостатньо, щоб вважати пакет готовим.

    Розробникам все ще потрібні чіткі відповіді на такі питання:

    • Як його встановити
    • Як ним користуватися
    • Які параметри є доступними
    • У якій формі мають бути дані
    • Як налаштувати його функціонування та вигляд
    • Які функції насправді підтримуються

    Якісна документація — це те, що подолує розрив між ситуацією, коли хтось думає:

    "I found this package."
    

    і моментом, коли він може з упевненістю сказати:

    "I can use this package."
    

    Яким буде подальший розвиток проекту

    Спочатку мета проекту react-native-paper-select була скромною: створити компонент вибору, який би природно інтегрувався у додатки, що вже використовують React Native Paper.

    З того часу він перетворився на набагато потужніший інструмент, який тепер підтримує кілька режимів вибору, різні стилі відображення, пошук, вибір за допомогою чіпів, розділені дані та ефективне відображення списків.

    Ще є багато можливостей для його подальшого вдосконалення.

    Жоден проект з відкритим кодом ніколи не стає повністю завершеним.

    Постійно з’являються нові пристрої, React Native сам продовжує випускати оновлення, змінюються очікування щодо дизайну, розвиваються вимоги до доступності, знову постають питання продуктивності, а розробники постійно надсилають корисні відгуки.

    Саме ця постійна еволюція робить підтримку такої бібліотеки справді цікавою.

    Заключні думки

    Робота над react-native-paper-select показала, що проект з відкритим кодом не обов’язково має починатися з великої ідеї.

    Часто все починається з невеликої, конкретної проблеми, з якою стикаєшся під час розробки чогось іншого.

    Ти сам її вирішуєш.

    Потім стає зрозуміло, що це рішення може допомогти іншим, хто стикається з тією самою проблемою.

    Тож ти його удосконалюєш.

    Ти належним чином його описуєш.

    Ти оприлюднюєш його.

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

    Ось історія створення react-native-paper-select.

    Якщо ваш проєкт використовує React Native Paper та вам потрібен гнучкий компонент для вибору або багатократного вибору, репозиторій знаходиться на GitHub, а сам пакет опублікований на npm.

    Будь-які відгуки, звіти про помилки та ваші внески завжди будуть корисними, якщо ви будете використовувати цей пакет.