React Final Form

compare with redux form

redux-form

formik

final-form

npm trend

Redux form

  • redux needed
  • Field, Fields, FieldArray
  • Higher-order component
  • handle by redux
  • Up to 27 KB gzipped

React Final form

  • final-form needed
  • Field (need other helpers)
  • Render props
  • Subscription based
  • Light weighted
  • redux-form like

APIs

  • Form
  • Field
  • FormSpy
  • useForm
  • useField
  • useFormState

react-final-form

final-form

  • FORM_ERROR

Form

import { Form } from 'react-final-form';

function BasicForm() {
  return (
     <Form
       onSubmit={(values) => {
         const {
           name,
           email,
         } = values;
       }}
       initialValues={{
         name: 'Stanney',
         email: 'rytass@rytass.com',
       }}
       validate={(values) => {
          const errors = {};
          if (!values.name) errors.name = 'Required';
          return errors;
       }}>
       {({
         submitError,
         handleSubmit,
       }) => (
         /* form view */ 
       )}
     </Form>
  );
} 

Field

import { Field } from 'react-final-form';

function BasicFormView({
  handleSubmit,
  submitError,
}) {
  return (
    <form onSubmit={handleSubmit}>
      <Field
        name="name"
        component={Input} />
      {submitError ? (
        <span>{submitError}</span>
      ) : null}
    </form>
  );
} 
function Input({
  input: {
    value,
    onChange,
  },
  meta: {
    error, // validate error
    submitError, // submit error
  },
}) {
  /* input view */
}

Errors handle

import { FORM_ERROR } from 'final-form'; 

<Form
  onSubmit={(values) => {
    const {
      name,
      email,
    } = values;

    if (name !== 'rytass') {
      return {
        name: 'Wrong name.',
      };
    }
    
    if (!email.match(emailReg)) {
      return {
        [FORM_ERROR]: 'Wrong Email format',
      };
    }

    return null;
  }}
  validate={(values) => {
    const errors = {};
    if (!values.name) errors.name = 'Required';
    return errors;
  }}>
</Form>

Field component

 => meta.submitError

Form render props

 => submitError

Field component

 => meta.error

Re-render problem

Form without subscription causing component re-render every field changes

<Form
  onSubmit={onSubmit}
  initialValue={myInits}>
  {({
    values,
    handleSubmit,
    submitError,
  }) => (
    /* form view */
  )}
</Form>
<Form
  onSubmit={onSubmit}
  initialValue={myInits}
  subscription={{
    submitting: true,
  }}>
  {({
    values,
    handleSubmit,
    submitError,
  }) => (
    /* form view */
  )}
</Form>

Form Spy

subscribe on Form props (must under Form component)

import { Form, FormSpy } from 'react-final-form';

<Form
  subscription={{
    submitting: true,
  }}>
  {({
    values,
  }) => (
    /* form view */
    <FormSpy subscription={{ values: true }}>
      {({
        values,
      }) => (
        /* re-render every field value change */
      )}
    </FormSpy>
  )}
</Form>

Field composing

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

<Form
  subscription={{
    submitting: true,
  }}>
  {({
    values,
  }) => (
    /* form view */
    <Field name="cityId">
      {({
        input: { value, onChange },
      }) => {
        const currentCity = cityZones.find(c => c.id === value) || null;

        return (
          <Field
            name="zoneId"
            options={currentCity ? currentCity.zones : []}
            component={Selector} />
        );
      }}
    </Field>
  )}
</Form>

Field need to bind with other Field (value change, onChange)

Helpers

I want...

  • Fields           composing Field yourself
  • FieldArray   use react-final-form-arrays
  • Wizard Form (multipage form) 

DEMO

React final form

By Travor Lee

React final form

compare with redux form

  • 171