Недавно у меня была возможность использовать замечательную библиотеку валидации в большом проекте React, в котором я участвовал.

Те из вас, кто знаком с формами в Интернете, знают, что проверка на стороне клиента является важным аспектом правильной работы с формами. После активного использования нескольких библиотек форм React я недавно остановился на Formik как на библиотеке форм, которую я предпочитаю. Formik привел меня к «да» (благодаря поддержке «из коробки»), который открыл мир эффективной и простой проверки форм на стороне клиента. Ага просто потрясающая своей простотой, скоростью и полнотой. Однако чего-то по-прежнему не хватало ...

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

Пример файла конфигурации JSON

{ "contact": { 
  "formname": "contact",
  "fields": [
    {
      "fieldname": "firstname",
      "input": "textinput",
      "label": "First Name",
      "yup": 
        "type": "string",
        "checks": [ 
          {
            "key": "minLength",
            "val": 2,
            "err": "is invalid"
          }
        ] 
      }
    } , {
      "fieldname": "email",
      "input": "textinput",
      "label": "Email Address",
      "yup": {
        "type": "string",
        "checks": [ 
          {
            "key": "email",
            "val": true,
            "err": "is not a valid email"
          }
        ] 
      }
    } , {
      "fieldname": "message",
      "input": "textareainput",
      "label": "Message",
      "yup": {
        "type": "string", 
        "checks: [
          { 
            "key": "maxLength", 
            "val": 100, 
            "err": "is too long"
          }
        ]
      } 
    }
  }
}

Средство визуализации компонента поля

import React from 'react'
import { Field } from 'formik'
import { contact } from 'config' // Above config file
export function switchInput (field) { 
  let f = { ...field }
  switch(f.input) {
    case 'TextArea':
      f['component'] = TextAreaInput
    default:
      f['component'] = TextInput
    return f
}
class FieldComponents extends React.Component { 
 
  renderField = (field, errors) => {
    let specific = this.switchInput(field)
    let props = {
      name: field.name,
      label: field.label,
      placeholder: field.placeholder ? field.placeholder : '',
      type: field.input ? field.input : 'text',
      errors 
    }
    return React.createElement(Field, props)
  }
  render() {
    contact.fields.map( field => this.renderField(field, this.form.errors)
  }
}
export default FieldComponents

Пример фактического компонента поля выглядит следующим образом

import React from 'react'
import { ErrorMessage } from 'formik'
const Label = ({ error, children, htmlFor, ...props }) => (children) ? <label {...props}>{children}</label> : ''
const TextInput = ({
  field: { name, value, ...field },
  form: { touched, errors, handleBlur, handleChange },
  label,
  type,
  disabled,
  placeholder
}) => {
  const error = errors[name]
  return (
    <div className={`form-group ${name} ${props.classes ? props.classes : ''}`}>
      {label &&
      <Label htmlFor={name} error={error} className="formlabel">
        {label}
      </Label>
      }
      <div>
        <input
          id={name}
          name={name}
          type={type}
          disabled={disabled}
          placeholder={placeholder}
          onBlur={handleBlur}
          onChange={handleChange}
          value={value || ''}
        />
        <ErrorMessage component="div" className="error" name={name} />
      </div>
    </div>
  )
}

Собирая все это вместе, мы используем замечательный пакет json-schema-to-yup, созданный Кристианом Мандрупом (в который, ваш покорный слуга, с течением времени были внесены незначительные изменения).

import React from 'react'
import { Formik, Field } from 'formik'
import { buildYup } from 'json-schema-to-yup'
import FieldComponents from 'FieldComponents'
class JSONValidatedForm extends React.Component {
function jsonShape(fields, name) {
      const shape = {
        title: name,
        type: 'object',
        log: true,
        required: [],
        properties: {}
      }
      const config = { errMessages: {} }
      fields.forEach(f => {
        let nullable = false
        const name = f.verb ? `${f.name}__${f.verb}` : f.name
        if (f.edit) {
          config.errMessages[name] = {}
          if (f.required) {
            shape.required.push(name)
            config.errMessages[name].required = `${f.label} is required`
            config.errMessages[name].string = `${f.label} is required`
          } else {
            nullable = true
          }
          if (f.yup && f.yup.type) {
            shape.properties[name] = { type: f.yup.type }
            f.yup.checks.forEach(check => {
              shape.properties[name][check.key] = check.val
              if (check.err) { config.errMessages[name][check.key] = check.err }
            })
            shape.properties[name].nullable = nullable || false
          }
        }
      })
    return buildYup(shape, config)
  }
render() {
<Formik
    validationSchema={this.jsonSchema()}
    validateOnChange={true}
    validateOnBlur={true}
    onSubmit={() => console.log('Submitted')}
    render={ (props, actions) => { return ( <FieldComponents ...props /> ) }
    />
  }
}

Как видите, в одном поле можно выполнить несколько проверок.

Наша схема JSON не совсем соответствует спецификации, поэтому метод jsonShape преобразовывает ее в форму, ожидаемую json-schema-to-yup, которая анализирует форму и затем предоставляет результат проверки Formik. Это всего лишь пример того, насколько гибким может быть этот стек проверки. Наслаждаться!