formik、react-final-form、react-hook-form、react-jsonschema-form 和 redux-form 都是用于在 React 应用中处理表单状态、验证和提交逻辑的库。它们通过抽象底层状态管理,帮助开发者避免重复编写样板代码,提升表单开发效率和可维护性。其中,redux-form 已被官方标记为不再维护;react-jsonschema-form 专注于基于 JSON Schema 自动生成表单 UI;其余三者(formik、react-final-form、react-hook-form)则提供更通用的表单控制能力,但在状态管理策略、性能优化方式和 API 设计上存在显著差异。
在 React 开发中,表单处理看似简单,实则涉及状态同步、验证、错误反馈、性能优化等复杂问题。本文从真实工程视角,对比五款主流表单库的技术实现、适用场景及关键取舍,助你做出合理架构决策。
redux-form 曾是早期 React 表单解决方案,但 官方已在 npm 页面明确标注为 deprecated,不再接受功能更新或重大修复。其核心问题在于将整个表单状态(包括每个字段的值、错误、是否触碰等)全部存入 Redux store,导致:
因此,新项目绝对不应选用 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))}
/>
);
formik:默认每次字段变更都会触发整个表单重渲染。虽提供 useField 和 FastField 优化,但需显式使用,易遗漏。react-final-form:基于订阅机制,字段组件仅在其依赖的状态(如 value、error)变化时更新,天然高性能。react-hook-form:非受控模式下,输入事件不经过 React state,仅在提交或验证时读取值,重渲染最少。react-jsonschema-form:性能取决于生成的字段数量和复杂度,大型动态表单可能需自定义 widget 优化。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 等),但复杂逻辑需扩展。formik:通过 FieldArray 处理动态列表,但嵌套对象需手动管理路径。react-final-form:内置 FieldArray,配合 final-form-arrays mutators,支持任意深度嵌套。react-hook-form:提供 useFieldArray Hook,专为动态列表优化,性能优异。react-jsonschema-form:通过 schema 中的 array 类型和 items 属性自动处理列表,但自定义交互有限。formik:广泛支持 Material UI、Ant Design 等,社区有成熟封装(如 formik-mui)。react-final-form:需为每个 UI 组件编写 adapter,但官方提供常见库示例。react-hook-form:通过 Controller 包装受控组件,集成灵活,社区适配器丰富。react-jsonschema-form:自带基础主题,可通过自定义 widget 替换任意字段渲染,但需额外开发成本。formik 当:react-final-form 当:react-hook-form 当:react-jsonschema-form 当:redux-form:对于大多数现代 React 项目,react-hook-form 是首选 —— 它平衡了性能、简洁性和灵活性。若团队更习惯受控模式且表单不复杂,formik 仍是可靠选择。react-final-form 适合对性能有极致要求的场景。而 react-jsonschema-form 则在特定动态表单领域无可替代。无论选择哪个,都应避免已废弃的 redux-form。
选择 formik 如果你偏好基于 render props 或自定义 Hook 的声明式表单 API,并且项目中已使用 Yup 进行验证。它对初学者友好,文档完善,适合中小型表单场景。但要注意其默认的全表单重渲染行为可能在大型表单中带来性能问题,需配合 useField 或 FastField 优化。
选择 react-final-form 如果你需要细粒度的订阅机制来避免不必要的重渲染,且希望表单状态与 UI 完全解耦。它基于订阅模式,仅当字段实际变化时才更新组件,适合高性能要求或复杂嵌套表单。但其学习曲线略陡,且依赖上下文传递,调试可能稍复杂。
选择 react-hook-form 如果你追求极致性能和简洁的 uncontrolled 组件集成方式。它利用原生 HTML 表单行为,最小化重渲染,验证逻辑可直接绑定到注册字段,非常适合大型表单或对性能敏感的应用。但需注意它不直接管理受控组件状态,与某些 UI 库集成时可能需要额外适配。
选择 react-jsonschema-form 如果你的表单结构由后端动态生成,并可通过 JSON Schema 描述。它能自动根据 schema 渲染完整表单 UI,大幅减少前端模板代码,适用于配置化表单、低代码平台或需要动态表单的场景。但灵活性受限于 schema 表达能力,复杂交互仍需自定义 widget。
不要在新项目中使用 redux-form。该库已被官方标记为不再维护(deprecated),且将所有表单状态存入 Redux store 会导致不必要的全局状态膨胀和性能开销。现有项目应逐步迁移到 react-hook-form 或 formik 等现代替代方案。
Visit https://formik.org to get started with Formik.
List of organizations and projects using Formik
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!
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!