mgr-forms-react: Простий компонент для найпростіших форм

Ви коли-небудь рахували, скільки форм ви робите під час розробки веб-додатків? І я не кажу про складних формах на зразок кастомного date-picker'а чи чогось складніше, а простих форм з трьома input, двома select і одним textarea?
Я не вважав. Але коли я почав писати чергове додаток на React і мені за один вечір довелося створити 5 різних форм — мені стало погано. Ну, а коли розробнику плохеет — розробник пише велосипед!

З таких міркувань на світ з'явилася поки ще сира, але вже використовувана мною в двох різних проектах, бібліотека для створення найпростіших форм на React. І я навіть виділю слово найпростіших, бо моя виріб навіть близько не стоїть поряд з такими проектами як React Forms або Formsy-React.
Замість картинки для залучення уваги — кількість однотипного коду, який нам усім доводиться писати заради створення найпростішої форми з одним полем.
Постановка завдання
Після деякого роздуми я усвідомив, що хочу мати під рукою React-компонет, готовий:
  • Рендери форму складається з найпростіших елементів (input select, textarea) кожен з яких легко настроюється (placeholder, default value, для input type, і так далі)...
  • … і має лише одну кнопку Submit, текст і поведінка якої налаштовується...
  • … не має готових стилів, але здатну приймати класи до своїх елементів.
  • Автоматично збирати дані з форми у плоский JSON об'єкт із заданими ключами.
  • Мати найпростіший механізм валідації полів у формі.
  • Показувати помилки, пов'язані як з якимось конкретним полем форми, так і загальну помилку для всієї форми.
Також через деякий час додалося ще одна вимога:
  • Якимось чином опис форми (але не сам рендеринг) повинен бути ідентичним для React і React Native.
Останні вимога з'явилася після рішення пиляти проект на React-native. Дуже вже не хотілося переписувати всі форми по другому разу.
Рішення
Варіантом, який в даний момент мене влаштовує майже за всіма пунктами став mgr-form-react. Що-то там ще не дороблено, щось забуте, але все настільки просто, що може бути додано дуже швидко і безболісно. Але давайте пройдемося по головним ідеям.
Відразу приклад найпростішої форми документації на GitHub:
import Form from "mgr-form-react";
export default TestComponent = () => {
// Опис полів форми
const controls = [
{
element: 'input', // тип поля. Може бути input select, textarea
id: 'Signup.Client.Form.Control.Name', // id DOM-елемента самого control'а
label: 'Client name', //текст показаний на лейблі поруч з полем
type: 'text' // тип input'а
}, {
element: 'select',
id: 'Signup.Client.Form.Control.Language',
label: 'Client language',
options: ['en', 'fr', 'it', 'de', 'ru', 'es'] // список можливих значень для select'а
}
];

// Опис поведінки та тексту кнопки у формі
const submit = {
text: 'Submit button text',
cb: (data) => {
console.log(data);
}
};

// Прапор мовець є форма активної
const editable = true;

return <Form controls={controls}
submit={submit}
editable={editable} />;
}

Ось власне і все. За кількістю коду коротше, звичайно, не стало, але мені приємніше розділяти зміст форми (тобто поля, які присутні у формі) від того, як форма рендерится.
Зараз готується такий же компонент для React-native. Плюс формат опису форми у вигляді JSON-документа я бачу в тому, що він може бути визначений на сервері і зчитуватися клиетном. Таким чином, нам не потрібно буде чекати 2 тижні в середньому поки клієнти оновлять свій додаток, щоб заборонити їм, припустимо, залишати фідбек без електронної адреси для зв'язку.
Поки що кількість параметрів форми не дуже велика, але в планах є додавання різних функцій, як наприклад, визначення поведінки onInput, onChange, onFocus, onBlur для полів форми, додавання кнопок, реєстрація власних типів полів (тобто якщо вам потрібно використовувати що-небудь більш складне, ніж input select або textarea, повинна бути можливість зареєструвати ваш компонент і використовувати його в описі форми) і так далі. Ну і, звичайно ж, проект відкритий для пул-реквестов.
Повний список параметрів компонентаПовна документація знаходиться на GitHub, тут же — просто список.
  • controls: масив з об'єктами, що описують поля форми. Порядок полів буде дотримано.
    — element
    — id
    — label
    — default
    — data
    — class
    — options
    — placeholder
    — type
    — validator
    — formatError
  • submit: об'єкт описує текст і поведінку кнопки у формі
    — text
    — cb
    — class
  • errors: об'єкт містить помилки які повинні бути показано у формі. Можливі поля — general для глобальної помилки всієї форми, або ж значення полів id об'єктів опису форми
  • editable: true або false, індикатор активності форми.

Приклад використання всіх можливих параметрів компонента
import Form from 'mgr-form-react';
export default TestComponent = () => {
const controls = [
{
element: 'input',
id: 'Signup.Client.Form.Control.Name',
label: 'Client name',
placeholder: 'Client name',
default: 'Default name value',
type: 'text',
data: 'name', // аргумент фунції cb в параметра submit для компонента форми буде мати поле з ключем "name" і значенням цього поля форми
validator: /^[A-Za-z0-9\s]{3,30}$/, // регулярне вираження для валідації значення поля
formatError: 'Wrong name format', // Помилка, показана у випадку, коли значення поля не проходить вадидацию
class: 'custom-input-class' // css-клас який буде доданий до цього поля форми
}, {
element: 'select',
id: 'Signup.Client.Form.Control.Language',
label: 'Client language',
options: ['en', 'fr', 'it', 'de', 'ru', 'es'],
default: 'en',
data: 'language',
class: 'custom-select-class'
}
];

const submit = {
text: 'Submit button text',
cb: (data) => {
console.log(data); // { name: "Default name value", language: "en" } у разі дефолтних значень кожного з полів
}
};

const errors = {
'Signup.Client.Form.Control.Name': 'Name field error that is generated by someone outside of the form (e.g. server response error)', // буде показано поруч з полем мають id 'Signup.Client.Form.Control.Name'.
general: 'A general error that will be shown under the form itself' // буде показано в окремому div е
};

const editable = true;

return <Form controls={controls}
submit={submit}
errors={errors}
editable={editable} />;
}

Стилі
Як було сказано вище, мені потрібний компонент, що генерує форми без стилів. Таким чином, стилі додаються вже незалежно від того, яким чином була створена форма — використовуючи mgr-form-react або яким-небудь іншим способом.
Структура класів у сгенерируемой формі буде наступною:
  • mgrform-form — клас обгортка для всієї форми
  • mgrform-control — клас — обгортка для кожного поля форми.
  • mgrform-has-error — клас, добавляющийся до mgrform-control у разі наявності помилки для даного поля (або помилки валідації, або помилки параметрів компонента)
  • mgrform-submit-btn — клас кнопки форми
  • mgrform-error — клас div елемента, що показує глобальну помилку форми.
  • до елементів з класами mgrform-control і mgrform-submit-btn додаються класи, задані властивості class об'єктів опису поля форми (об'єкта в масиві controls) і об'єкта submit.
Висновок
Я цілком розумію, що це хороший приклад велосипедостроения. Однак, мені дуже зручно описувати прості форми, які не потребують складної логіки всередині себе, у якому-небудь виді, можливому для збереження в окремий файл, з можливістю подальшого перевикористання в інших проектах.
Само собою я відкритий для критики, і, зрозуміло, буду радий, якщо комусь небудь ця виріб збереже 5-10 хвилин робочого часу, які можна буде витратити на ще одну чашку кави.
P. S. я не особливо гугл існуючі рішення схожого типу, буду радий, якщо хтось вкаже мені на них. Спасибі
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.