formik vs react-final-form vs react-hook-form vs react-jsonschema-form vs redux-form
React 表单管理库技术选型指南
formikreact-final-formreact-hook-formreact-jsonschema-formredux-form类似的npm包:

React 表单管理库技术选型指南

formikreact-final-formreact-hook-formreact-jsonschema-formredux-form 都是用于在 React 应用中处理表单状态、验证和提交逻辑的库。它们通过抽象底层状态管理,帮助开发者避免重复编写样板代码,提升表单开发效率和可维护性。其中,redux-form 已被官方标记为不再维护;react-jsonschema-form 专注于基于 JSON Schema 自动生成表单 UI;其余三者(formikreact-final-formreact-hook-form)则提供更通用的表单控制能力,但在状态管理策略、性能优化方式和 API 设计上存在显著差异。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
formik034,385585 kB8364 个月前Apache-2.0
react-final-form07,440215 kB3749 个月前MIT
react-hook-form044,5621.25 MB12214 天前MIT
react-jsonschema-form015,670-2016 年前Apache-2.0
redux-form012,5161.45 MB4973 年前MIT

React 表单库深度对比:Formik、Final Form、React Hook Form、JSONSchema Form 与 Redux Form

在 React 开发中,表单处理看似简单,实则涉及状态同步、验证、错误反馈、性能优化等复杂问题。本文从真实工程视角,对比五款主流表单库的技术实现、适用场景及关键取舍,助你做出合理架构决策。

⚠️ 首要结论:Redux Form 已淘汰

redux-form 曾是早期 React 表单解决方案,但 官方已在 npm 页面明确标注为 deprecated,不再接受功能更新或重大修复。其核心问题在于将整个表单状态(包括每个字段的值、错误、是否触碰等)全部存入 Redux store,导致:

  • 每次输入都触发全局状态更新,引发不必要的重渲染
  • Redux DevTools 日志被大量表单 action 淹没,干扰业务逻辑调试
  • 表单状态与业务状态耦合,违反单一职责原则

因此,新项目绝对不应选用 redux-form,现有项目应制定迁移计划。

🧩 核心设计哲学对比

formik:约定优于配置的声明式表单

formik 采用受控组件模型,通过 useFormik Hook 或 <Formik> 组件提供完整的表单上下文。它内置了常见模式(如字段注册、错误处理、提交流程),并深度集成 Yup 验证库。

// Formik 示例
import { useFormik } from 'formik';
import * as Yup from 'yup';

const MyForm = () => {
  const formik = useFormik({
    initialValues: { email: '', password: '' },
    validationSchema: Yup.object({
      email: Yup.string().email().required(),
      password: Yup.string().min(8).required()
    }),
    onSubmit: values => alert(JSON.stringify(values, null, 2))
  });

  return (
    <form onSubmit={formik.handleSubmit}>
      <input
        name="email"
        value={formik.values.email}
        onChange={formik.handleChange}
        onBlur={formik.handleBlur}
      />
      {formik.touched.email && formik.errors.email ? <div>{formik.errors.email}</div> : null}
      
      <input
        name="password"
        type="password"
        value={formik.values.password}
        onChange={formik.handleChange}
        onBlur={formik.handleBlur}
      />
      {formik.touched.password && formik.errors.password ? <div>{formik.errors.password}</div> : null}
      
      <button type="submit">Submit</button>
    </form>
  );
};

react-final-form:基于订阅的精准更新

react-final-form 采用发布-订阅模式,表单状态独立于 React 组件树。每个字段组件通过 useField 订阅自身所需的状态片段,仅当相关状态变化时才重渲染。

// React Final Form 示例
import { Form, Field } from 'react-final-form';
import arrayMutators from 'final-form-arrays';

const MyForm = () => (
  <Form
    onSubmit={values => alert(JSON.stringify(values, null, 2))}
    mutators={{ ...arrayMutators }}
    validate={values => {
      const errors = {};
      if (!values.email) errors.email = 'Required';
      else if (!/^[^@]+@[^@]+\.[^@]+$/.test(values.email)) errors.email = 'Invalid email';
      if (!values.password) errors.password = 'Required';
      else if (values.password.length < 8) errors.password = 'Min 8 chars';
      return errors;
    }}
    render={({ handleSubmit, pristine, invalid }) => (
      <form onSubmit={handleSubmit}>
        <Field name="email">
          {({ input, meta }) => (
            <>
              <input {...input} placeholder="Email" />
              {meta.touched && meta.error && <div>{meta.error}</div>}
            </>
          )}
        </Field>
        
        <Field name="password">
          {({ input, meta }) => (
            <>
              <input {...input} type="password" placeholder="Password" />
              {meta.touched && meta.error && <div>{meta.error}</div>}
            </>
          )}
        </Field>
        
        <button type="submit" disabled={pristine || invalid}>Submit</button>
      </form>
    )}
  />
);

react-hook-form:拥抱原生的高性能方案

react-hook-form 默认采用非受控组件模式,通过 register 将字段注册到内部状态,利用浏览器原生表单行为减少 React 状态同步开销。验证逻辑可直接附加到注册过程。

// React Hook Form 示例
import { useForm } from 'react-hook-form';

const MyForm = () => {
  const { register, handleSubmit, formState: { errors } } = useForm({
    defaultValues: { email: '', password: '' }
  });

  return (
    <form onSubmit={handleSubmit(values => alert(JSON.stringify(values, null, 2)))}>
      <input
        {...register('email', {
          required: 'Required',
          pattern: { value: /^[^@]+@[^@]+\.[^@]+$/, message: 'Invalid email' }
        })}
        placeholder="Email"
      />
      {errors.email && <div>{errors.email.message}</div>}
      
      <input
        {...register('password', {
          required: 'Required',
          minLength: { value: 8, message: 'Min 8 chars' }
        })}
        type="password"
        placeholder="Password"
      />
      {errors.password && <div>{errors.password.message}</div>}
      
      <button type="submit">Submit</button>
    </form>
  );
};

react-jsonschema-form:Schema 驱动的自动化表单

react-jsonschema-form 接收 JSON Schema 和 UI Schema,自动生成完整表单 UI。适用于表单结构动态变化或由后端定义的场景。

// React JSONSchema Form 示例
import Form from 'react-jsonschema-form';

const schema = {
  type: 'object',
  properties: {
    email: { type: 'string', format: 'email', title: 'Email' },
    password: { type: 'string', minLength: 8, title: 'Password' }
  },
  required: ['email', 'password']
};

const uiSchema = {
  password: { 'ui:widget': 'password' }
};

const MyForm = () => (
  <Form
    schema={schema}
    uiSchema={uiSchema}
    onSubmit={({ formData }) => alert(JSON.stringify(formData, null, 2))}
  />
);

📊 关键能力横向对比

1. 性能表现:重渲染控制

  • formik:默认每次字段变更都会触发整个表单重渲染。虽提供 useFieldFastField 优化,但需显式使用,易遗漏。
  • react-final-form:基于订阅机制,字段组件仅在其依赖的状态(如 value、error)变化时更新,天然高性能。
  • react-hook-form:非受控模式下,输入事件不经过 React state,仅在提交或验证时读取值,重渲染最少。
  • react-jsonschema-form:性能取决于生成的字段数量和复杂度,大型动态表单可能需自定义 widget 优化。

2. 验证支持

  • formik:原生支持同步/异步验证函数,与 Yup 集成最佳,支持 schema 级联验证。
  • react-final-form:支持同步/异步验证,可字段级或表单级定义,但无内置 schema 验证库集成。
  • react-hook-form:验证规则直接绑定到 register,支持同步/异步、resolver(如 Yup、Zod),验证触发策略灵活(onChange/onBlur/onSubmit)。
  • react-jsonschema-form:验证由 AJV 库基于 JSON Schema 执行,覆盖标准格式(email、uri 等),但复杂逻辑需扩展。

3. 复杂表单场景(数组、嵌套)

  • formik:通过 FieldArray 处理动态列表,但嵌套对象需手动管理路径。
  • react-final-form:内置 FieldArray,配合 final-form-arrays mutators,支持任意深度嵌套。
  • react-hook-form:提供 useFieldArray Hook,专为动态列表优化,性能优异。
  • react-jsonschema-form:通过 schema 中的 array 类型和 items 属性自动处理列表,但自定义交互有限。

4. 与 UI 库集成

  • formik:广泛支持 Material UI、Ant Design 等,社区有成熟封装(如 formik-mui)。
  • react-final-form:需为每个 UI 组件编写 adapter,但官方提供常见库示例。
  • react-hook-form:通过 Controller 包装受控组件,集成灵活,社区适配器丰富。
  • react-jsonschema-form:自带基础主题,可通过自定义 widget 替换任意字段渲染,但需额外开发成本。

🛠️ 何时选用哪个?

选择 formik 当:

  • 团队熟悉受控组件模式
  • 项目已使用 Yup 进行数据验证
  • 表单规模中等,性能非首要瓶颈
  • 需要快速上手,重视开发体验

选择 react-final-form 当:

  • 表单包含大量字段或复杂嵌套
  • 对重渲染性能有严格要求
  • 偏好函数式、解耦的设计风格
  • 能接受稍高的学习成本

选择 react-hook-form 当:

  • 追求极致性能,尤其大型表单
  • 希望减少状态管理样板代码
  • 项目使用 TypeScript(类型推导优秀)
  • 愿意采用非受控组件模式

选择 react-jsonschema-form 当:

  • 表单结构由后端动态生成
  • 需要快速搭建配置化表单
  • 适用于低代码/无代码平台
  • 能接受 UI 和交互的一定限制

避免 redux-form

  • 所有新项目
  • 任何对性能或可维护性有要求的场景

💡 总结建议

对于大多数现代 React 项目,react-hook-form 是首选 —— 它平衡了性能、简洁性和灵活性。若团队更习惯受控模式且表单不复杂,formik 仍是可靠选择。react-final-form 适合对性能有极致要求的场景。而 react-jsonschema-form 则在特定动态表单领域无可替代。无论选择哪个,都应避免已废弃的 redux-form

如何选择: formik vs react-final-form vs react-hook-form vs react-jsonschema-form vs redux-form

  • formik:

    选择 formik 如果你偏好基于 render props 或自定义 Hook 的声明式表单 API,并且项目中已使用 Yup 进行验证。它对初学者友好,文档完善,适合中小型表单场景。但要注意其默认的全表单重渲染行为可能在大型表单中带来性能问题,需配合 useFieldFastField 优化。

  • react-final-form:

    选择 react-final-form 如果你需要细粒度的订阅机制来避免不必要的重渲染,且希望表单状态与 UI 完全解耦。它基于订阅模式,仅当字段实际变化时才更新组件,适合高性能要求或复杂嵌套表单。但其学习曲线略陡,且依赖上下文传递,调试可能稍复杂。

  • react-hook-form:

    选择 react-hook-form 如果你追求极致性能和简洁的 uncontrolled 组件集成方式。它利用原生 HTML 表单行为,最小化重渲染,验证逻辑可直接绑定到注册字段,非常适合大型表单或对性能敏感的应用。但需注意它不直接管理受控组件状态,与某些 UI 库集成时可能需要额外适配。

  • react-jsonschema-form:

    选择 react-jsonschema-form 如果你的表单结构由后端动态生成,并可通过 JSON Schema 描述。它能自动根据 schema 渲染完整表单 UI,大幅减少前端模板代码,适用于配置化表单、低代码平台或需要动态表单的场景。但灵活性受限于 schema 表达能力,复杂交互仍需自定义 widget。

  • redux-form:

    不要在新项目中使用 redux-form。该库已被官方标记为不再维护(deprecated),且将所有表单状态存入 Redux store 会导致不必要的全局状态膨胀和性能开销。现有项目应逐步迁移到 react-hook-formformik 等现代替代方案。

formik的README

Formik.js

Build forms in React, without the tears.


Stable Release Blazing Fast gzip size license Discord

Visit https://formik.org to get started with Formik.

Organizations and projects using Formik

List of organizations and projects using Formik

Authors

Contributing

This monorepo uses yarn, so to start you'll need the package manager installed.

To run E2E tests you'll also need Playwright set up, which can be done locally via npx playwright install. Afterward, run yarn start:app and in a separate tab run yarn e2e:ui to boot up the test runner.

When you're done with your changes, we use changesets to manage release notes. Run yarn changeset to autogenerate notes to be appended to your pull request.

Thank you!

Contributors

Formik is made with <3 thanks to these wonderful people (emoji key):


Jared Palmer

💬 💻 🎨 📖 💡 🤔 👀 ⚠️

Ian White

💬 🐛 💻 📖 🤔 👀

Andrej Badin

💬 🐛 📖

Adam Howard

💬 🐛 🤔 👀

Vlad Shcherbin

💬 🐛 🤔

Brikou CARRE

🐛 📖

Sam Kvale

🐛 💻 ⚠️

Jon Tansey

🐛 💻

Tyler Martinez

🐛 📖

Tobias Lohse

🐛 💻

This project follows the all-contributors specification. Contributions of any kind welcome!

Related

  • TSDX - Zero-config CLI for TypeScript used by this repo. (Formik's Rollup configuration as a CLI)

Apache 2.0 License.