React Final Form

with yup

Forms in React

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      email: '',
      password: ''
    };
  }

  handleInputChange = (event) => {
    const { name, target } = event.target;

    this.setState({
      [name]: value
    });
  }
  ...
}

Validate Forms in React

handleInputChange = (e) => {
  const { name, value } = e.target;
  let errors = this.state.errors;

  switch (name) {
    case 'email': 
      errors.email = Regex.email.test(value)
        ? ''
      : 'Email is not valid!';
      break;
    case 'password': 
      errors.password = value.length < 8
        ? 'Password must be 8 characters long!'
      : '';
      break;
    default:
      break;
  }
  
  this.setState({errors, [name]: value});
}

Show error on blur in React

handleBlur = (e) => {
  const { name, value } = e.target;
  if (this.state[name] !== value) {
    this.setState({ dirty: true });
  }
}

render() {
  const { dirty, touched } = this.state;
  return (
    <input
    	name="username"
    	onFocus={this.setState({ touched: true })}
  	onBlur={this.handleBlur} />
    {touched && dirty && errors.username 
     && <span>errors.username</span>}
  );
}

React Form Libraries

 

17k stars

11k stars

almost 5k stars

by @erikras

Why React Final Form?

"For several years, I (@erikras) actively maintained the first big form library in the React community, Redux Form. During those years, I learned many lessons, about open source and React, and saw hundreds of forms use cases from around the world. As Redux Form grew in popularity (and bundle size), I received a lot of feedback from the community. React Final Form is my answer the concerns of the community."

React Final Form's Philosphy

React Final Form's Goals

  • Strongly Typed
  • Modularity / Agnostic
  • Minimal Bundle Size
  • High Performance

Architecture

React Final Form is a thin React wrapper for Final Form, which is a subscriptions-based form state management library that uses the Observer pattern, so only the components that need updating are re-rendered as the form's state changes.

Getting Started

npm install final-form react-final-form
import { Form, Field } from 'react-final-form'


const MyForm = () => (
  <Form
    onSubmit={onSubmit}
    validate={validate}
    render={formProps => (
      <form onSubmit={formProps.handleSubmit}>
      	//...
      </form>
    )}
  />
)

React Final Form Example

<Form
  onSubmit={onSubmit}
  validate={validate}
  render={props => (
    <form onSubmit={props.handleSubmit}>

        <Field
          name="username"
          render={({ input, meta }) => (
            <div>
              <input {...input} />
              {meta.errror && (
                <span>{meta.error}</span>
              )}
            </div>
          )}
        </Field>

      <button type="submit">Submit</button>
    </form>
  )}
</Form>
  • active
  • dirty
  • dirtyFields
  • dirtySinceLastSubmit
  • error
  • errors
  • hasSubmitErrors
  • hasValidationErrors
  • initialValues
  • invalid
  • modified
  • pristine
  • submitError
  • submitErrors
  • submitFailed
  • submitSucceeded
  • submitting
  • touched
  • valid
  • validating
  • values
  • visited

FormApi (props)

  • isEqual
  • name
  • parse
  • render
  • subscription
  • validate
  • validateFields
  • value

FieldApi (props)

  • afterSubmit
  • allowNull
  • beforeSubmit
  • children
  • component
  • defaultValue
  • format
  • formatOnBlur
  • initialValue

<Field render={({input}) => {

  • name
  • onBlur
  • onChange
  • onFocus
  • value
  • active
  • data
  • dirty
  • dirtySinceLastSubmit
  • error
  • initial
  • invalid
  • modified
  • pristine
  • submitError
  • submitFailed
  • submitSucceeded
  • submitting
  • touched
  • valid
  • validating
  • visited

<Field render={({meta}) => {

React Final Form

+

YUP

yup

import { object, string, date } from 'yup'

const validationSchema = {
  object().shape({
    email: string()
      .email()
      .required("Required"),
    password: string()
      .required("No password provided.")
      .min(8, "Password is too short - should be 8 chars minimum.")
      .matches(/(?=.*[0-9])/, "Password must contain a number."),
    dateOfTravel: date().when("fromFuture", {
      is: true,
      then: date()
        .required("What time did you travel from?")
        .min(new Date(), "You said you were from the future!")
    })
  })
}

add yup validationSchema

import { object, string, date } from 'yup'

const validationSchema = {
  object().shape({
    email: string()
      .email()
      .required("Required"),
    password: string()
      .required("No password provided.")
      .min(8, "Password is too short - should be 8 chars minimum.")
      .matches(/(?=.*[0-9])/, "Password must contain a number."),
    dateOfTravel: date().when("fromFuture", {
      is: true,
      then: date()
        .required("What time did you travel from?")
        .min(new Date(), "You said you were from the future!")
    })
  })
}

Field with schema validate

name = 'email'

validateField = (value) => {
  const { schema } = this.validationSchema.field[this.name];
  
  try {
    schema.validateSync(value);
  } catch (e) {
    return e.errors && e.errors[0];
  }
}

render() {
  return (<Field name={this.name} validate={this.validateField}>)
}

Show error message from yup

<Field  {...props} 
  name={name}
  validate={this.validateField}
>
  {({ input, meta }) => (
    <input {...input} />
    {meta.touched && meta.error && <span>{meta.error}</span>}
  )}
</Field>
  

Conditional Fields

const Condition = ({ when, is, children }) => (
  <Field name={when} subscription={{ value: true }}>
    {({ input: { value } }) => is(Number(value)) ? children : null
    }
  </Field>
);
<Condition when="isFromFuture" is={value => !!value}>
  <Field
    name="dateOfTravel"
  />
</Condition>

Focus on Error

npm install final-form-focus
import React from 'react'

import { Form, Field } from 'react-final-form'

import createDecorator from 'final-form-focus'

const focusOnErrors = createDecorator()

<Form
  decorators={[ focusOnErrors ]
/>
Made with Slides.com