Forms are basically an essential part of many websites and apps. As with everything related to the JS there are many options to choose from. Doing forms in React should be easy and painless, which means input validation and form state management should be easily doable. With minimal performance hits, of course.
Since React is just a UI library it doesn’t come with a form solution out of the box. Choosing the right form library can be a tricky issue, as there are numerous ones to choose from. And of course, that means reading all of the unnecessary documentation related to each one. This blog will compare three that are mostly used in React world.
The technical part
A lot of times when a developer needs to choose an external lib for something he will check for performance issues, speed, size, etc. Let us check some numbers! First of all, download statistic.
Number of downloads in the last 6 months
Formik is still number one, as far as downloads are concerned. React-hook-form is neck to neck with Formik. And last, the Final Form, which is not popular as the two above. Check the picture below for more detailed stats.
More detailed information about libs
Based on these stats React-Hook-Form leads in most areas. It is regularly updated, has fewer open issues, the build is pretty small, and most importantly, it has no dependencies. Why is this important? Well, generally, the fewer dependencies, the better. That means that your lib isn’t dependable on any other source. Best way to describe this is with the (now) famous “left-pad” disaster. The author removed his lib from npm and basically broke the internet with that (file with 11 lines of code). So, if your lib doesn’t depend on any other, you are safe from situations like this.
Installation is pretty simple and straightforward for all of them. You can use npm or yarn for adding depth to your application.
npm install formik | react-hook-form | final-form react-final-form
--save
Formik
Before starting with Formik, let us see what is the main difference between Formik and other libs. Formik is using controlled components (inputs). Controlled component is a component that gives control of changing the value to the library itself (React is guided by the principle “the state is the single source of truth”). In controlled components, every time the user changes the input value, the form is also updated and it saves the data in its state.
Formik uses its own components like <Field/> and <Form/> to render UI. <Field /> will by default show <input /> element, but it is configurable with params. Check the docs for more information. Formik also provides <Formik/> component that is used as a wrapper for included form. You can pass props like initialValues, validate, onSubmit etc.
Basic <Form/> structure with Formik
Formik uses Form-level validation. This is useful because you have complete access to all of your form’s values and props whenever the function runs, so you can validate dependent fields at the same time. Validation with Formik also needs to be explicitly developed and applied to each input, or through the help of validation libraries like Yup. Formik accepts either validation prop, or validationSchema prop, depending on what is being used to validate. Check here on GITS. The biggest drawback Formik has is that on every change it re-renders the whole form, which can significantly impact performance. If the Form is smaller in size, this may not cause significant issues, but on a bigger form, this could impact application performance.
React is all about composition, and all of the label, <Field>, and <ErrorMessage> components shouldn’t be copied. With Formik (and other libs) abstraction is an option. Formik uses a hook called useField that will pass all of the props to a new component.
React-Hook-Form
By the definition of its author, React-Hook-Form is “Performant, flexible and extensible forms with easy-to-use validation.” lib is used for creating dynamic and preformant forms in React and React Native. As the name suggests it was built when React version 16.8 (2018) was introduced, so it’s relatively newer and was built to leverage the power of React hooks. As such, in terms of performance, it beats all others. Because it uses React Hooks every state is isolated which results in re-rendering kept to the minimum. This could come in handy when creating complex forms with a lot of user data. Also, since this was built with React Hooks, it means that class-based React is out of the picture.
Basic validation with React-Hook-Form
As you can see in the above snippet, the code is quite readable (if you understand hooks, naturally ). It uses ref to handle state changes, so it causes minimal re-renders. It exposes the useForm hook, which has a couple of helper methods to register state, handle form submissions, and keep track of errors. Basically what renders after deconstruction is ref, name, onChange, and onBlur events.
React-Hook-Form provides some of its own validation (as shown in a snippet above) or it accepts schema validator (as Yup or other). Unlike Formik, React-Hook-Form needs yupResolver to use Yup as a dependency.
Abstraction is a little bit harder here since register props must be passed manually.
Check it on a sandbox!
Also, this lib provides a form builder which eases up the process a lot!
Final-form
This library is made by the author redux-form. That’s why it fixed a lot of mistakes from Redux-Form. React Final Form is a lightweight form library written in core JavaScript that acts as a wrapper around Final Form.
React Final Form uses the observer design pattern in which the components subscribe to specific events. Instead of the whole form re-rendering, only the fields that have been subscribed re-render. So basically it combines the functionality of Fomrik and React-Hook-Form. Also, it is very small in size (only 3.2kb minified)
The usage of final-form is very similar to Formik. It uses <Form/> and <Field/> components. <Form/> is the parent component that takes all the props for the management of form and <Field/> renders an input. The component created by <Field/> has its own state that is managed by the <Form/> tag.
Basic usage with react-final-form
Unlike Formik and React-Hook-Form, Final-form doesn’t support resolvers and validationSchema. That means that all validation must be done by hand. There are some hacks and workarounds, but again, hacks are not meant for coding. The cool thing about Final-form is that it provides Submitting prop that lets you know if the form submission is in progress, so the submit button is also disabled.
Conclusion
As with everything in the coding world, to see which lib is the best, you must decide on your own. All of them have some strengths and weaknesses. React-hook-form appears to be the fastest growing and most regularly updated. Also, it makes great usage of React Hooks and component isolation which will make forms snapper and more performant. And that removes unnecessary re-renders. Formik has a large community behind it because it’s the longest-running form library of the lot.
Its declarative nature makes the code easily readable, which is great for developer experience and React-final-form is the smallest one. In terms of validation, the best approach also depends on your preferences. Yup is great and very extensive, while manual validation gives more control over the components. Choosing the right one will mostly depend on the project for which it is needed.