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
2. Decorators (some official decorators)
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
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