Frontend Development 12 min read

Which React Form Library Wins? A Deep Dive into Formik, Final‑Form, and React‑Hook‑Form

This article compares three popular React form libraries—Formik, Final‑Form, and React‑Hook‑Form—examining their popularity, bundle size, usage patterns, advantages, and drawbacks to help developers choose the most suitable solution for their projects.

Code Mala Tang
Code Mala Tang
Code Mala Tang
Which React Form Library Wins? A Deep Dive into Formik, Final‑Form, and React‑Hook‑Form

Forms are everywhere and are a required part of every website. When building web applications with React, handling forms is unavoidable.

Choosing a third‑party library can be daunting because there are many options. Selecting a library solely based on GitHub stars is not always wise; you need to read the documentation, examine code examples, and try it out to see if it fits your project.

The main options discussed are Formik, Final‑Form, and React‑Hook‑Form (redux‑form is mentioned but ignored as outdated).

Usage Comparison

Formik

Formik has the most GitHub stars and download counts, making it the most widely used library.

It requires rendering a Formik component directly in the component’s render method, which can clutter the render logic. You also have to manually map handleChange , handleBlur , etc., to input elements, although the library provides Field and ErrorMessage components to simplify this.

Formik does not include built‑in validation; you must write your own validation function or integrate a library such as Yup. It also does not fully support hooks—using the useFormik hook disables Field , ErrorMessage , and FieldArray components.

<code>import React from "react";
import { Formik } from "formik";

const Basic = () => (
  <div>
    <h1>在你的应用任何地方!</h1>
    <Formik
      initialValues={{ email: "", password: "" }}
      validate={(values) => {
        const errors = {};
        if (!values.email) {
          errors.email = "必填";
        } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) {
          errors.email = "无效的电子邮件地址";
        }
        return errors;
      }}
      onSubmit={(values, { setSubmitting }) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          setSubmitting(false);
        }, 400);
      }}
    >
      {({ values, errors, touched, handleChange, handleBlur, handleSubmit, isSubmitting }) => (
        <form onSubmit={handleSubmit}>
          <input type="email" name="email" onChange={handleChange} onBlur={handleBlur} value={values.email} />
          {errors.email && touched.email && errors.email}
          <input type="password" name="password" onChange={handleChange} onBlur={handleBlur} value={values.password} />
          {errors.password && touched.password && errors.password}
          <button type="submit" disabled={isSubmitting}>提交</button>
        </form>
      )}
    </Formik>
  </div>
);

export default Basic;
</code>

You must render the Formik component directly, which can make the render section messy.

You need to manually map handleChange , handleBlur , etc., to inputs.

Formik lacks built‑in validation; you must write validation logic or use a library like Yup.

Formik does not fully support hooks; using useFormik disables several helper components.

Final‑Form

Final‑Form, created by the author of redux‑form, is well‑known. It uses a Form component and Field components to pass props to inputs.

Integrating Final‑Form with other React components (e.g., react‑select) can be cumbersome, and it also lacks built‑in validation, requiring you to write validation functions yourself. It does not provide native support for Yup or Joi.

<code>import React from "react";
import ReactDOM from "react-dom";
import Styles from "./Styles";
import { Form, Field } from "react-final-form";

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const onSubmit = async (values) => {
  await sleep(300);
  window.alert(JSON.stringify(values, 0, 2));
};

const App = () => (
  <Styles>
    <h1>React Final Form示例</h1>
    <h2>密码/确认验证</h2>
    <a href="https://final-form.org/react" target="_blank" rel="noopener noreferrer">阅读文档</a>
    <Form
      onSubmit={onSubmit}
      validate={(values) => {
        const errors = {};
        if (!values.username) errors.username = "必填";
        if (!values.password) errors.password = "必填";
        if (!values.confirm) errors.confirm = "必填";
        else if (values.confirm !== values.password) errors.confirm = "必须匹配";
        return errors;
      }}
      render={({ handleSubmit, form, submitting, pristine, values }) => (
        <form onSubmit={handleSubmit}>
          <Field name="username">
            {({ input, meta }) => (
              <div>
                <label>用户名</label>
                <input {...input} type="text" placeholder="用户名" />
                {meta.error && meta.touched && <span>{meta.error}</span>}
              </div>
            )}
          </Field>
          <Field name="password">
            {({ input, meta }) => (
              <div>
                <label>密码</label>
                <input {...input} type="password" placeholder="密码" />
                {meta.error && meta.touched && <span>{meta.error}</span>}
              </div>
            )}
          </Field>
          <Field name="confirm">
            {({ input, meta }) => (
              <div>
                <label>确认</label>
                <input {...input} type="password" placeholder="确认" />
                {meta.error && meta.touched && <span>{meta.error}</span>}
              </div>
            )}
          </Field>
          <div className="buttons">
            <button type="submit" disabled={submitting}>提交</button>
            <button type="button" onClick={form.reset} disabled={submitting || pristine}>重置</button>
          </div>
          <pre>{JSON.stringify(values, 0, 2)}

)} />

); ReactDOM.render(

, document.getElementById("root"));

React‑Hook‑Form

Discovered on Reddit, React‑Hook‑Form is praised for its simplicity. You create a form with the useForm hook and register inputs via the register function.

<code>import React from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit, watch, errors } = useForm();
  const onSubmit = data => console.log(data);

  console.log(watch("example")); // monitor input value by name

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="example" defaultValue="test" ref={register} />
      <input name="exampleRequired" ref={register({ required: true })} />
      {errors.exampleRequired && <span>这个字段是必填的</span>}
      <input type="submit" />
    </form>
  );
}
</code>

React‑Hook‑Form is the easiest to use among the three. It works well with other component libraries (e.g., react‑select) via the setValue function. It also provides built‑in validation helpers and supports integration with validation libraries such as Yup.

<code>import React from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit } = useForm();
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={register({ required: true, maxLength: 20 })} />
      <input name="lastName" ref={register({ pattern: /^[A-Za-z]+$/i })} />
      <input name="age" type="number" ref={register({ min: 18, max: 99 })} />
      <input type="submit" />
    </form>
  );
}
</code>

React‑Hook‑Form relies on uncontrolled components, so you do not need to manage state and onChange handlers; you only set defaultValue . According to its documentation, it minimizes unnecessary re‑renders, has the lowest mount time, and therefore offers the best performance. Its bundle size is tiny (≈8.6 kB gzipped) and it has no external dependencies, resulting in faster load times and reduced project complexity.

Conclusion

React‑Hook‑Form is currently the easiest library to use, with excellent documentation. Its only limitation is that it works only with function components; projects still using class components cannot adopt it.

Frontend DevelopmentReactReact-Hook-FormFinal-FormForm LibrariesFormik
Code Mala Tang
Written by

Code Mala Tang

Read source code together, write articles together, and enjoy spicy hot pot together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.