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

от автора

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

Из таких вот соображений на свет появилась пока еще сырая, но уже используемая мной в двух разных проектах, библиотека для создания простейших форм на React. И я даже выделю слово простейших, потому как моя поделка даже близко не стоит рядом с такими проектами как React Forms или же Formsy-React.

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

Постановка задачи

После некоторого размышления я осознал, что хочу иметь под рукой React-компонет, готовый:

  • Рендерить форму состоящую из простейших элементов (input, select, textarea) каждый из которых легко настраивается (placeholder, default value, type для input, и так далее)…
  • … и имеющую одну лишь кнопку 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. я не особо гуглил существующие решения похожего типа, буду рад, если кто-нибудь укажет мне на них. Спасибо

ссылка на оригинал статьи https://habrahabr.ru/post/314088/


Комментарии

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

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