Choose A Form Library

Motivation

  • Already tried much form libraries
  • Wanna give every form library a chance and understand why are they so popular
  • Choose a form library with no doubts next time

Redux Form

React Final Form

React Hook Form

Formik

Candidates

Redux Form

By Hand

Candidates

star: 27,818

issues: 600

size: 13kb

download: 1,400,515

createdAt: 2017

star: 6,530

issues: 354

size: 3.2kb

download: 342,563

createdAt: 2017

(2021/08/08)

star: 22,527

issues: 8

size: 8.6kb

download: 949,488

createdAt: 2019

star: 12,567

issues: 495

size: 26.3kb

download: 353,969

createdAt: 2015

Candidates

Redux Form

  • In most cases, we don't need sharing form state globally
  • If you do so, you will take some times to consider performance characteristics

Article:

How They Implement with React

HOC

Render Props

Hook

Redux-Form

React Final Form

Formik

Formik

React Hook Form

...

React Final Form

Formik

Redux Form

Typescript Support
Render Performance Optimizable
Sub-Form Composing
Built-in / Validation Library Support By yourself
Still up-to-date
Allow Sharing Form State Globally
Well Documentation

React Final Form

Typescript Support
Render Performance Optimizable
Sub-Form Composing
Built-in / Validation Library Support None (But can use yup)
Still up-to-date
Allow Sharing Form State Globally other state manager
Well Documentation

React Final Form

Downsides

1. No official validation library

<Form
  onSubmit={this.submitHandler}
  validate={async (values) => {
    const validator = validationSchema(values)

    try {
      await validator.validate(values, { abortEarly: false });
    } catch (err) {
      const errors = err.inner.reduce((formError, innerError) => ({
        ...formError,
        [innerError.path]: innerError.message,
      }), {});

      return errors;
    }
  }}
 >
 </Form>

(implement middleware by yourself)

React Final Form

Downsides

2. No FieldArray

import { Form } from "react-final-form";
import arrayMutators from "final-form-arrays";
import { FieldArray } from "react-final-form-arrays";

<Form
  onSubmit={onSubmit}
  mutators={{
    ...arrayMutators
  }}
>
  // ...
</Form>
  • extra dependencies final-form-arrays and react-final-form-arrays

React Final Form

Upsides

1. rendering optimizable (subscription)

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

<Form
  onSubmit={onSubmit}
  subscription={{ submitting: true }}
>
  // ...
</Form>

React Final Form

Upsides

import { Form } from "react-final-form";
import createDecorator from 'final-form-focus';

const focusOnError = createDecorator();

<Form
  onSubmit={onSubmit}
  decorators={[focusOnError]}
  subscription={{ submitting: true }}
>
  // ...
</Form>
  • final-form-focus: focus and scroll to the first field with an error when form submit
  • Write your own decorator (implement form api)

Formik

Typescript Support
Render Performance Optimizable
Sub-Form Composing
Built-in / Validation Library Support Yup ...
Still up-to-date
Allow Sharing Form State Globally other state manager
Well Documentation

Formik

Downsides

1. Render Optimization

(from 2018 till now)

Formik

Downsides

1. Render Optimization

  • FastField

(no hook version)

(not recommended by author)

Formik

1. No peer dependencies

2. Easier to write and config

3. Fully support 'Yup' for validation, and also recommended by author (no more if/else)

  • react-final-form (depends on final-form)
  • redux-form (depends on redux)

Upsides

import { Formik, Field } from 'formik';

<Formik
  initialValues={{}}
  onSubmit={(values, actions) => {}}
>
  // ...
  <Field name="firstName" component={Component} />
</Formik> 

Formik

So...

Why does

so popular?

Google 'React form library'

React Hook Form

Typescript Support
Render Performance Optimizable Already optimized
Sub-Form Composing
Built-in / Validation Library Support Yup, Zod...
Still up-to-date
Allow Sharing Form State Globally other state manager
Well Documentation

React Hook Form

Downsides

  • register / control may cause confusing when passing through components
  • props spreading make props uncontrollable
const { register, control, handleSubmit } = useForm<FormInputs>({
  defaultValues: {
    firstName: "123",
  },
});

<input {...register("firstName")} />
<FirstNameWatched control={control} />

1. Special api namings

FormProvider / useFormContext

React Hook Form

Downsides

use FormProvider / useFormContext

const methods = useForm<FormInputs>({
  defaultValues: {
    firstName: "123",
  },
});

<FormProvider {...methods}>
  <Component />
</FormProvider>

function Component() {
  const { register } = useFormContext();
  
  // ...
}

1. Special api namings

React Hook Form

Downsides

  • Whenever you need to get the most actual data you need to use useWatch or watch, but defaultValue won't be watchable when first render.
const { register, control, handleSubmit } = useForm<FormInputs>({
  defaultValues: {
    firstName: "123",
  },
});

const firstName = useWatch({
  control,
  name: "firstName",
  defaultValue: "default",
});
// Get 'default' at first render
console.log(firstName);

2. Asynchronicity

React Hook Form

Upsides

const { register, control, handleSubmit } = useForm<FormInputs>({
  defaultValues: {
    firstName: "123",
    authors: [{ id: "1", name: "author1" }],
  },
});

return (
  <>
    <form onSubmit={handleSubmit}>
      <input {...register('firstName')} />
    </form>
    <Modal>
      <form>
        // render authors
      </form>
    </Modal>
  </>
);

1. Sub-Form Composing is easier

React Hook Form

Upsides

const { register, watch, control, handleSubmit } = useForm<FormInputs>({
  defaultValues: {
    firstName: "123",
    authors: [{ id: "1", name: "author1" }],
  },
});

// don't watch any fields here, ex: watch('firstName'),
// will prevent re-rendering as default

return (
  <form onSubmit={handleSubmit}>
    <input {...register('firstName')} />
  </form>
);

2. Hook everywhere and render optimized

Conclusions

建立一份表單的速度(快到慢)

formik > react-hook-form > react-final-form

可擴充性(高到低)

react-final-form >> react-hook-form > formik

驗證表單輕鬆程度

formik >> react-hook-form >= react-final-form

(有很多官方範例教你/套件)

(大多自己想辦法、或翻 issue)

效能(好到差)

react-hook-form >= react-final-form >>> formik

(看 subscription 寫的如何)

學習曲線(容易到難)

formik > react-hook-form > react-final-form

(包含了已學過,經過一段時間後,回來複習怎麼使用的學習過程)

Conclusions

Cases Form Library
專案小、求快速 formik
專案大、求擴充維護性 react-final-form
懶得想、只想一招打天下 react-hook-form

Validation Library

yup

import * as Yup from 'yup';

export function sponsorFormValidationSchema() {
  return Yup.object().shape({
    title: Yup.string().required('Title is required'),
    buttonText: Yup.mixed()
      .when('buttonDisplay', {
        is: true,
        then: Yup.string().required('Button text is required'),
      }),
    buttonLinkURL: Yup.mixed()
      .when('buttonDisplay', {
        is: true,
        then: Yup.mixed().when('buttonLinkType', {
          is: 'URL',
          then: Yup.string().required().url(LINK_FORMAT_ERROR),
        }),
      }),
    buttonLinkPDF: Yup.mixed()
      .when('buttonDisplay', {
        is: true,
        then: Yup.mixed().when('buttonLinkType', {
          is: 'FILE',
          then: Yup.string().required('File upload is required'),
        }),
      }),
  });
}

Thanks

Choose A Form Library

By Travor Lee

Choose A Form Library

  • 234