formik、react-final-form、react-hook-form、react-jsonschema-form 和 redux-form 都是用于在 React 应用中处理表单状态、验证和提交逻辑的库,而 formik-material-ui 是 formik 与 Material-UI 组件的集成桥接包。这些库通过封装表单的复杂性,帮助开发者减少样板代码、提升可维护性,并支持复杂的验证、异步提交和字段联动等场景。它们在状态管理方式、性能优化策略、API 设计哲学以及与 UI 库的集成能力上存在显著差异。
在 React 开发中,表单处理看似简单,实则暗藏复杂性 —— 状态同步、验证反馈、错误处理、性能优化等问题常让开发者陷入泥潭。本文从真实工程视角,深入对比 formik、formik-material-ui、react-final-form、react-hook-form、react-jsonschema-form 和 redux-form 六个主流方案,助你做出精准技术选型。
redux-form 已被官方标记为废弃(deprecated)。其 GitHub 仓库和 npm 页面均明确建议迁移到其他方案。原因在于它将整个表单状态存入 Redux store,导致:
// redux-form (已废弃,勿用于新项目)
import { Field, reduxForm } from 'redux-form';
const MyForm = ({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<Field name="email" component="input" type="email" />
</form>
);
export default reduxForm({ form: 'myForm' })(MyForm);
formik-material-ui 也已停止维护。其 npm 页面注明 "This library is no longer maintained"。它仅为 Formik 与旧版 Material-UI(v4)的胶水代码,新项目应直接使用 MUI v5 的 TextField 等组件手动绑定 Formik 或切换至更现代的方案。
// formik-material-ui (已废弃)
import { TextField } from 'formik-material-ui';
import { Field } from 'formik';
<Field component={TextField} name="username" />;
结论:新项目应完全排除
redux-form和formik-material-ui。
formik 和 react-final-form 默认采用受控模式 —— 表单值由 React state 驱动,每次输入都更新 state 并触发重渲染。
// Formik (受控模式)
import { useFormik } from 'formik';
function MyForm() {
const formik = useFormik({
initialValues: { email: '' },
onSubmit: values => alert(JSON.stringify(values)),
});
return (
<form onSubmit={formik.handleSubmit}>
<input
id="email"
name="email"
type="email"
onChange={formik.handleChange}
value={formik.values.email}
/>
<button type="submit">Submit</button>
</form>
);
}
// React Final Form (受控模式示例)
import { Form, Field } from 'react-final-form';
const MyForm = () => (
<Form
onSubmit={values => console.log(values)}
render={({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<Field name="email">
{({ input }) => <input {...input} type="email" />}
</Field>
<button type="submit">Submit</button>
</form>
)}
/>
);
react-hook-form 默认采用非受控模式 —— 表单值由 DOM 自身管理,仅在需要时(如提交、验证)读取,极大减少重渲染。
// React Hook Form (非受控模式)
import { useForm } from 'react-hook-form';
function MyForm() {
const { register, handleSubmit } = useForm();
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email')} type="email" />
<button type="submit">Submit</button>
</form>
);
}
性能影响:在大型表单(>20 字段)中,非受控模式可减少 50%+ 的重渲染次数。
formik 提供两种 API:Render Props(<Formik> 组件)和自定义 Hook(useFormik),偏向声明式。react-final-form 主要通过 Render Props 和 HOC,强调函数式组合。react-hook-form 完全基于 Hooks,API 极简,符合现代 React 开发习惯。所有活跃库均支持同步/异步验证,但集成方式不同。
// Formik + Yup
import * as Yup from 'yup';
const validationSchema = Yup.object({
email: Yup.string().email().required(),
});
const formik = useFormik({
validationSchema,
// ...
});
// React Final Form + 自定义验证函数
const validate = values => {
const errors = {};
if (!values.email) errors.email = 'Required';
return errors;
};
<Form validate={validate} />
// React Hook Form + Yup (通过 resolver)
import { yupResolver } from '@hookform/resolvers/yup';
const { register } = useForm({
resolver: yupResolver(validationSchema),
});
注意:
react-hook-form的验证默认在提交时触发,可通过mode选项改为实时验证(onChange/onBlur)。
处理复杂数据结构时,各库能力差异明显。
// Formik 处理数组
{formik.values.friends.map((_, index) => (
<input
key={index}
{...formik.getFieldProps(`friends[${index}].name`)}/>
))}
// React Final Form 使用 FieldArray
import { FieldArray } from 'react-final-form-arrays';
<FieldArray name="friends">
{({ fields }) => (
fields.map((name, index) => (
<Field name={`${name}.name`} component="input" />
))
)}
</FieldArray>
// React Hook Form 使用 useFieldArray
import { useFieldArray } from 'react-hook-form';
const { fields, append } = useFieldArray({ control, name: 'friends' });
{fields.map((field, index) => (
<input key={field.id} {...register(`friends.${index}.name`)} />
))}
经验之谈:
react-hook-form的useFieldArray在动态增删字段时性能最优,因其内部使用非受控策略。
现代项目多使用 UI 组件库,集成便捷性至关重要。
// Formik + MUI v5 (手动绑定)
import { TextField } from '@mui/material';
<TextField
{...formik.getFieldProps('email')}
error={!!formik.errors.email}
helperText={formik.errors.email}
/>
// React Hook Form + MUI v5
<Controller
name="email"
control={control}
render={({ field, fieldState }) => (
<TextField
{...field}
error={!!fieldState.error}
helperText={fieldState.error?.message}
/>
)}
/>
关键区别:
react-hook-form对于受控组件(如 MUI 的TextField)需使用Controller包装,而formik可直接通过getFieldProps绑定。但react-hook-form的register可直接用于原生 input,更轻量。
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 新项目启动 | react-hook-form | 性能最优、API 简洁、TypeScript 支持完善、社区活跃 |
| 已有 Formik 项目 | 继续使用 formik | 迁移成本高,除非遇到性能瓶颈 |
| JSON Schema 驱动表单 | react-jsonschema-form | 自动生成 UI,适合低代码/配置化场景 |
| 超大型动态表单 | react-final-form | 订阅机制精细,可优化特定字段重渲染 |
| 遗留 Redux 系统 | 评估迁移至 react-hook-form | redux-form 已废弃,长期维护风险高 |
react-hook-form:它代表了现代 React 表单处理的最佳实践 —— 性能、简洁性、灵活性兼备。redux-form 和 formik-material-ui 不应出现在新代码库中。react-jsonschema-form 能极大提升效率;若团队已深度 invested in Formik 且无性能问题,可暂不迁移。表单虽小,却关乎用户体验与应用性能。选对工具,事半功倍。
选择 formik 如果你偏好基于 Render Props 或自定义 Hook 的声明式 API,且项目使用受控组件模式。它适合中等复杂度的表单,提供良好的 TypeScript 支持和丰富的社区生态。但需注意其默认对整个表单进行重渲染,对于大型表单可能需要配合 useMemo 或 Field 组件优化性能。
选择 formik-material-ui 仅当你已在项目中同时使用 formik 和 Material-UI(v4),并希望快速将 Formik 的状态绑定到 MUI 输入组件。该库仅为适配层,不提供独立表单逻辑,且官方已明确停止维护,新项目应避免使用,建议直接使用 MUI v5 自带的 @mui/x-date-pickers 等集成方案或手动绑定。
选择 react-final-form 如果你需要高性能的订阅机制(仅重渲染变更字段)、支持复杂嵌套表单结构,或偏好函数式组件与高阶组件(HOC)结合的 API。它基于 Final Form 引擎,提供细粒度控制,适合大型或动态表单,但学习曲线略陡,且社区活跃度近年有所下降。
选择 react-hook-form 如果你追求极致性能(默认非受控模式减少重渲染)、简洁的 Hook API 和出色的 TypeScript 体验。它特别适合现代 React 应用,支持受控与非受控混合模式,验证灵活(可集成 Yup、Zod 等),是当前主流推荐方案,尤其适用于新项目。
选择 react-jsonschema-form 如果你的表单结构由 JSON Schema 动态驱动(如低代码平台、配置化表单生成器)。它能根据 schema 自动生成 UI,大幅减少手写表单代码,但定制 UI 或复杂交互时灵活性受限,适合 schema 驱动场景而非通用表单开发。
选择 redux-form 仅当你维护一个遗留系统且已深度耦合 Redux 状态树。该库已官方标记为不再维护(deprecated),新项目绝对不应采用。其将整个表单状态存入 Redux store,导致不必要的全局状态膨胀和性能开销,现代替代方案(如 react-hook-form)在架构上更优。
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!