React的验证表单的高序组件 - revalidation

2017-06-11      367      JavaScript
项目简介

Revalidation

Higher Order Component for Forms in React

Revalidationlets you write your forms as stateless function components , taking care of managing the local form state as well as the validation. Revalidation also works with classes and will support other React like libraries Preact or Inferno in the future.

Getting started

Install revalidation via npm or yarn.

npm install --save revalidation

Use Case

Form handling sounds trivial sometimes, but let’s just take a second to think about what is involved in the process. We need to define form fields, we need to validate the fields, we also might need to display errors according to the fact if the input validates, furthermore we need to figure out if the validation is instant or only after clicking on a submit button and so on and so forth.

Revalidationtakes care of running your predicate functions against defined field inputs, by separating the validation from the input. For example we would like to define a number of validation rules for two inputs, name and random .

const validationRules = {
  name: [
    [ isGreaterThan(5),
      `Minimum Name length of 6 is required.`
    ],
  ],
  random: [
    [ isGreaterThan(7), 'Minimum Random length of 8 is required.' ],
    [ hasCapitalLetter, 'Random should contain at least one uppercase letter.' ],
  ]
}

And imagine this is our input data.

const inputData = { name: 'abcdef', random: 'z'}

We would like to have a result that displays any possible errors.

Calling validatevalidate({inputData, validationRules)should return

{name: true, 
 random: [
    'Minimum Random length of 8 is required.', 
    'Random should contain at least one uppercase letter.' 
]}

Revalidate does exactly that, by defining an initial state and the validation rules it takes care of updating and validating any React Form Component.

Example

We might have a stateless function component that receives a prop form , which include the needed field values.

import React, {Component} from 'react'

const Form = ({ form, onSubmit }) =>
  (
    <div className='form'>
      <div className='formGroup'>
        <label>Name</label>
        <input
          type='text'
          value={form.name}
        />
      </div>
      <div className='formGroup'>
        <label>Random</label>
        <input
          type='text'
          value={form.random}
        />
      </div>
      <button onClick={() => onSubmit(form)}>Submit</button>
    </div>
  )

Next we might have a defined set of rules that we need to validate for given input values.

const validationRules = {
  name: [
    [isNotEmpty, 'Name should not be  empty.']
  ],
  random: [
    [isLengthGreaterThan(7), 'Minimum Random length of 8 is required.'],
    [hasCapitalLetter, 'Random should contain at least one uppercase letter.'],
  ]
}

Further more we know about the inital form state, which could be empty field values.

const initialState = {password: '', random: ''}

Now that we have everything in place, we import Revalidation.

import Revalidation from 'revalidation'

Revalidation needs the initial state, the validation rules, an error component and an options object as well as the Form component itself. The error component is simply telling Revalidation how to render the error messages. For example we only want to display one error at a time.

const ErrorComponent = ({errorMsgs}) => <div className='error'>{head(errorMsgs)}</div>

Revalidate will only render the error component when a field is invalid and the errorMsg prop is always an array. So in this case we want to access and render the first error message.

The options object currently supports two options: validateSingle and instantValidation .

  • validateSingle : Is useful if when we only want to validate one field a time. (default: false)
  • instantValidation : Set to true if new prop form values should be validated instantly. (default: false)
const option1 = {validateSingle: false} // validate all fields as soon as the first field changes f.e.
const option2 = {validateSingle: true} // validate per changed values. 
const option3 = {instantValidation: false} // ignore validating any passed in props updates, f.e. only validating on submit click.
const option4 = {instantValidation: true} // validate as soon as passed in props have been updated.

Finally we enhance the Form component.

const enhanced = Revalidation(
  initialState,
  validationRules,
  ErrorComponent,
  {validateSingle: false}
)

export default enhanced(Form)

This enables us to rewrite our Form component, which accepts a reValidation prop now.

const getValue = e => e.target.value

const Form = ({ reValidation : {form, validate, valid, errors = {}, validateAll}, onSubmit }) =>
  (
    <div className='form'>
      <div className='formGroup'>
        <label>Name</label>
        <input
          type='text'
          value={form.name}
          onChange={e => validate('name', getValue(e))}
        />
        { errors.name }
      </div>
      <div className='formGroup'>
        <label>Random</label>
        <input
          type='text'
          value={form.random}
          onChange={e => (validate('random', getValue(e))}
        />
        { errors.random }
      </div>
      <button onClick={() => validateAll(onSubmit)}>Submit</button>
    </div>
  )

reValidtion returns an object containing:

  • form : form values
  • validate : validation function expecting form name and value, f.e.validate('name', 'foo')
  • valid : caclulated validation state, f.e. initially disabling the submit button when a form is rendered.
  • errors : the errors object either containing nothing or a error component for every defined form field.
  • validateAll : validate all fields at once, also accepts a callback function that will be called incase of a valid state.

Where and how to display the errors and when and how to validate is responsibilty of the form not Revalidation. Another aspect is that the form props can als be provided when rendering the enhanced Form component.

<Form
    onSubmit={this.onSubmit}
    form={{name: 'foobar', random: ''}}
/>

Either define an initial state or use form props to define an actual form state. Revalidation will check for props first and then fallback to the initial state when none is found.

Also check the example for more detailed insight into how to build more advanced forms, f.e. validating dependent fields.

Clone the repository go to the examples folder and run the following commands:

yarn install
npm start.