Final Form logo

Final Form

框架无关的表单状态管理库,基于订阅模式实现精确渲染控制,由 Redux Form 作者 Erik Rasmussen 创建。

表单校验框架无关React订阅模式

Final Form 是框架无关的表单状态管理库,采用观察者模式通过订阅机制精确控制字段级渲染,支持 React、Vue、Web Components 等多框架,零依赖且体积仅约 10.9KB。

Final Form

框架无关的表单状态管理库,基于订阅模式实现精确渲染控制,由 Redux Form 作者 Erik Rasmussen 创建。

技术简介说明

Final Form 是一个**框架无关(Framework-Agnostic)**的表单状态管理库,由 Erik Rasmussen 于 2018 年创建。Erik Rasmussen 此前是 Redux Form 的作者,在深度反思 Redux Form 的架构问题后(过度依赖 Redux、受控模式导致性能瓶颈、与 Redux 强耦合),他重新设计了 Final Form,将核心逻辑从 React 和 Redux 中完全解耦,实现了纯粹的表单状态管理引擎。

Final Form 的核心架构基于观察者模式(Observer Pattern)和订阅机制。每个字段通过 subscription 订阅特定的状态切片(如 valueserrorstouched 等),只有订阅了变化字段的组件才会触发重渲染,避免了表单中单次按键触发整个组件树更新的问题。这种设计使得 Final Form 既可以在 React 中使用(通过 react-final-form),也可以在 Vue(vue-finalform)、Web Components(CorpusculeJS)等其他框架中使用。

截至 2026 年,Final Form 核心包(final-form)周下载量约 60 万次,React 绑定包(react-final-form)周下载量约 50 万次。2025 年完成了从 Flow 到 TypeScript 的重大迁移(v5.0),2026 年 5 月发布 v5.0.1 修复了大量 bug。不过,项目主要由 Erik Rasmussen 一人维护,社区对项目长期可持续性存在一定担忧。

基本信息

快速上手

安装

# 安装核心包和 React 绑定
npm install final-form react-final-form
 
# yarn
yarn add final-form react-final-form
 
# pnpm
pnpm add final-form react-final-form

如需数组字段支持,还需安装:

npm install final-form-arrays react-final-form-arrays

如需提交时自动聚焦到第一个错误字段:

npm install final-form-focus

基础配置

Final Form 无需额外配置文件。React 中使用 <Form><Field> 组件:

import { Form, Field } from 'react-final-form'
 
// 验证函数
const validate = (values) => {
  const errors = {}
  if (!values.name) {
    errors.name = '姓名不能为空'
  }
  if (!values.email) {
    errors.email = '邮箱不能为空'
  } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) {
    errors.email = '邮箱格式不正确'
  }
  return errors
}
 
function MyForm() {
  const onSubmit = (values) => {
    console.log('提交数据:', values)
  }
 
  return (
    <Form
      onSubmit={onSubmit}
      validate={validate}
      render={({ handleSubmit, submitting, hasValidationErrors }) => (
        <form onSubmit={handleSubmit}>
          <Field name="name" component={TextInput} label="姓名" />
          <Field name="email" component={TextInput} label="邮箱" />
          <button type="submit" disabled={submitting}>
            提交
          </button>
          {hasValidationErrors && <p>请修正表单错误</p>}
        </form>
      )}
    />
  )
}

最小示例

最简单的使用方式,无需验证:

import { Form, Field } from 'react-final-form'
 
function App() {
  return (
    <Form
      onSubmit={(values) => alert(JSON.stringify(values))}
      render={({ handleSubmit }) => (
        <form onSubmit={handleSubmit}>
          <Field name="firstName" component="input" placeholder="名" />
          <Field name="lastName" component="input" placeholder="姓" />
          <button type="submit">提交</button>
        </form>
      )}
    />
  )
}

核心概念与架构

核心概念

  1. 框架无关设计(Framework-Agnostic):核心状态管理逻辑与任何 UI 框架无关,通过适配器模式支持不同框架。final-form 是纯 JavaScript 状态引擎,react-final-form 是其 React 绑定层。

  2. 订阅模式(Subscription Pattern):每个 &lt;Field&gt; 组件通过 subscription 属性声明需要订阅的状态切片(如 valueerrortouched),只有被订阅的状态变化时才会触发该字段的重渲染。这是 Final Form 性能优化的核心机制。

  3. 状态存储(State Store):Final Form 内部维护一个完整的表单状态对象(包含 valueserrorstoucheddirtysubmitting 等),所有状态变更通过内部事件系统广播给订阅者。

  4. Mutators(变更器):可扩展的状态修改机制,允许注册自定义的状态变更操作。例如 final-form-arrays 提供了 pushpopremoveswap 等数组操作 mutator。

  5. 装饰器模式(Decorator):可以监听表单状态变化并执行副作用,例如 final-form-calculate 可以在特定字段变化时自动计算衍生值,final-form-submit-listener 可以监听提交事件。

  6. 受控与渲染函数:React 绑定支持 render 函数、component 属性和 children 函数三种渲染模式,灵活适配不同场景。

架构设计

┌──────────────────────────────────────────────┐
│             用户界面层(React / Vue / ...)      │
│   <Form> + <Field> / useForm() / useField()  │
└────────────────┬─────────────────────────────┘
                 │ 订阅 / 通知
┌────────────────▼─────────────────────────────┐
│          框架绑定层(react-final-form)          │
│   React Context + 订阅转发 + 生命周期管理       │
└────────────────┬─────────────────────────────┘
                 │ API 调用
┌────────────────▼─────────────────────────────┐
│            核心引擎层(final-form)              │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │ 状态管理  │  │ 订阅系统  │  │ 验证调度  │   │
│  └──────────┘  └──────────┘  └──────────┘   │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │ Mutators │  │ 装饰器   │  │ 提交控制  │   │
│  └──────────┘  └──────────┘  └──────────┘   │
└────────────────┬─────────────────────────────┘
                 │ 扩展
┌────────────────▼─────────────────────────────┐
│             插件层(按需引入)                    │
│  final-form-arrays / final-form-calculate     │
│  final-form-focus / final-form-set-field-data │
└──────────────────────────────────────────────┘

工作原理

  1. 创建表单实例时,final-form 初始化内部状态对象和订阅管理器
  2. &lt;Field&gt; 组件注册时,向引擎订阅特定状态切片(subscription
  3. 用户输入时,字段通过 onChange 更新内部状态
  4. 状态变更触发订阅系统,仅通知订阅了该状态切片的字段组件
  5. 验证函数在每次值变化或 validate 触发时执行,结果同步到 errors 状态
  6. 提交时 handleSubmit 执行最终验证,通过后调用 onSubmit 回调

核心特性

  • 框架无关设计:核心逻辑与 React 解耦,可适配 Vue、Web Components 等任意框架
  • 订阅模式精确渲染:每个字段按需订阅状态切片,避免不必要的重渲染,大表单性能优秀
  • 零依赖 & 小体积:核心包无外部依赖,final-form + react-final-form 合计 gzip 约 10.9 kB
  • 模块化扩展(Mutators):数组操作、字段计算、自动聚焦等功能按需引入,不增加未使用代码
  • 灵活的验证模式:支持同步验证、异步验证(Promise)、字段级验证和表单级验证
  • 完整的生命周期控制initialValueskeepDirtyOnReinitializedestroyOnUnregister 等细粒度配置
  • TypeScript 全面支持:v5.0 从 Flow 完整迁移到 TypeScript,提供完善的类型定义
  • React 19 兼容:v7.0.0 已添加 React 19 peer dependency 支持
  • 装饰器系统:支持计算字段、提交监听、焦点管理等横切关注点的插件化扩展
  • 多步骤表单支持:v5.0.1 新增 ignoreUnregister 选项,支持字段取消注册后跳过验证

生态图

核心生态系统

Final Form 生态
├── 核心
│   ├── final-form(框架无关状态引擎,v5.0.1)
│   └── react-final-form(React 绑定,v7.0.1)
├── 框架绑定
│   ├── vue-finalform(Vue 绑定,by egoist)
│   └── CorpusculeJS Form(Web Components 绑定)
├── 官方工具包
│   ├── final-form-arrays(数组字段 mutators)
│   ├── react-final-form-arrays(React 数组字段组件)
│   ├── react-final-form-listeners(字段状态监听组件)
│   ├── final-form-focus(提交时自动聚焦错误字段)
│   ├── final-form-calculate(计算衍生字段值)
│   ├── final-form-submit-listener(监听提交事件)
│   ├── final-form-set-field-data(设置字段自定义数据)
│   └── final-form-set-field-touched(设置字段 touched 状态)
├── 第三方扩展
│   ├── mui-rff(Material UI + React Final Form 封装)
│   ├── frontier-forms(GraphQL mutation 驱动表单)
│   ├── data-driven-forms(JSON Schema → 表单渲染引擎)
│   └── define-form / react-define-form(强类型 TypeScript 绑定)
└── 验证集成
    └── 无官方 Schema 适配器(需手写验证函数或自行封装)

关键依赖

  • final-form:核心引擎(React 绑定的 peer dependency)
  • React ≥ 16.8(使用 react-final-form 时)
  • TypeScript ≥ 4.x(v5.0+ 类型定义)
  • 无其他运行时依赖

相关插件/扩展

包名说明
final-form-arrays数组字段操作 mutators(push、pop、remove、swap、move 等)
react-final-form-arraysReact 数组字段渲染和编辑组件
final-form-focus提交失败时自动聚焦到第一个含错误的字段
final-form-calculate基于其他字段值自动计算衍生字段
react-final-form-html5-validationHTML5 原生验证替代 Field 组件
mui-rffMaterial UI 组件与 React Final Form 的封装集成
data-driven-formsJSON Schema 驱动的表单渲染引擎(Red Hat 出品)

社区生态

  • GitHub 组织下共 14 个仓库
  • GitHub Open Issues 约 87 个,Open PRs 约 17 个
  • 社区规模中等,相比 React Hook Form 活跃度较低
  • 2025 年社区出现弃用请求讨论(issue #1045),反映社区对项目长期维护的担忧
  • PkgPulse 健康分 77/100(Good),流行度分 90/100

适用场景

  • 跨框架表单需求:同一套表单逻辑需要在 React、Vue 或 Web Components 中复用的项目,Final Form 的框架无关设计是独特优势
  • 大表单性能优化:50+ 字段的大型表单,订阅模式可精确控制渲染范围,避免全局重渲染
  • 模块化表单架构:需要按需引入数组操作、计算字段、焦点管理等扩展功能的复杂表单
  • 遗留项目维护:基于 Redux Form 的遗留项目迁移路径——Redux Form → Final Form 是最自然的演进方向
  • 细粒度渲染控制:需要精确控制哪些组件在什么条件下重渲染的场景,subscription 机制提供了极细的渲染粒度
  • 自定义表单引擎:需要深度定制表单行为(自定义 mutators、装饰器、提交流程)的高级场景
  • 轻量级表单需求:追求小体积(gzip 约 10.9 kB)且零依赖的项目

开发与工程化

开发流程

# 克隆核心仓库
git clone https://github.com/final-form/final-form.git
cd final-form
 
# 安装依赖
yarn install
 
# 运行测试
yarn test
 
# 构建
yarn build
 
# React 绑定开发
git clone https://github.com/final-form/react-final-form.git
cd react-final-form
yarn install
yarn test

构建产物

  • ES Module(dist/final-form.es.js
  • CommonJS(dist/final-form.cjs.js
  • UMD(dist/final-form.umd.js
  • TypeScript 类型声明(dist/*.d.ts

工程化最佳实践

  1. 验证逻辑封装:由于 Final Form 不提供 Schema 验证适配器,建议封装通用的验证工具函数,将 Yup/Zod Schema 转换为 Final Form 的 validate 函数
  2. Mutators 按需引入:只在需要时引入 final-form-arrays 等扩展,避免打包冗余代码
  3. Subscription 精确配置:为 &lt;Field&gt; 组件配置最小化的 subscription,只订阅必要状态
  4. 配合 TypeScript 使用:v5.0 后全面支持 TypeScript,建议启用严格模式获取完整类型安全
  5. 与 CI/CD 集成:运行 yarn test 确保测试通过,结合类型检查保证代码质量

CI/CD 集成

  • GitHub Actions 自动化测试和发布
  • 使用 size-limit 监控包体积变化
  • npm 自动发布到 registry

性能与安全

性能特点

  • 订阅模式精确更新:每次按键只触发订阅了该字段 value 状态的组件重渲染,其余组件不受影响
  • 零依赖轻量核心:核心包无外部依赖,减少 JS bundle 体积和解析时间
  • 模块化按需加载:数组操作、计算字段等功能按需引入,未使用的代码不会进入 bundle
  • 状态比较优化:内部使用浅比较避免不必要的订阅者通知

性能优化建议

  • &lt;Field&gt; 配置 subscription=&#123;&#123; value: true, error: true &#125;&#125; 等最小化订阅,避免订阅整个表单状态
  • 大表单中使用 formatparse 函数时注意性能,避免每次按键执行昂贵的转换逻辑
  • 异步验证使用 debounce 策略,避免频繁触发远程校验
  • 数组字段使用 final-form-arrays 的 mutator 操作,避免手动重建数组导致的全量更新

安全注意事项

  • 前端验证仅为 UX 优化,表单数据提交前必须进行服务端二次验证
  • 避免在 initialValues 中注入不可信数据,防止 XSS
  • 敏感数据(密码、信用卡)不应存储到 localStorage 或通过 persist 插件持久化
  • 异步验证调用 API 时注意 CSRF 防护和请求鉴权

已知性能瓶颈

  • Issue #336:超大表单(100+ 字段且全部订阅完整状态)可能出现性能问题
  • Subscription 配置不当(如订阅了整个 formState)会退化为全量重渲染
  • 相比 React Hook Form 的 uncontrolled + ref 方案,订阅模式在极致性能场景略逊一筹

技术对比

Final Form vs React Hook Form vs Formik vs TanStack Form(2026)

维度Final FormReact Hook FormFormikTanStack Form
架构订阅模式 + 框架无关非受控 + useRef受控(State)Headless + 框架无关
体积(gzip)~10.9 KB(合计)~9.4 KB~12.8 KB~12 KB
渲染优化订阅精确控制非受控最少重渲染每次输入触发重渲染精确订阅
TypeScript★★★★★(v5.0)★★★★★★★★☆☆★★★★★
Schema 验证❌ 无内置支持✅ 内置 resolvers✅ validationSchema✅ 适配器模式
框架支持React/Vue/WC仅 React仅 ReactReact/Vue/Solid/Angular
学习曲线中等(订阅概念)中等(register API)中高
生态规模较小(14 个仓库)庞大(行业领先)庞大但维护放缓中等(TanStack 生态)
维护状态单人维护积极维护维护模式积极维护
React 19✅ v7.0.0⚠️ 兼容补丁
周下载量~50 万~1200 万~340 万增长中

核心差异

  • Final Form:框架无关 + 订阅模式,精确控制渲染,但无 Schema 验证支持,生态较小
  • React Hook Form:React 专属,性能最优,生态最完善,2026 年的默认选择
  • Formik:API 设计优雅,学习曲线低,但受控模式性能较差,维护活跃度下降
  • TanStack Form:同为框架无关设计,生态较新但发展迅速,TanStack 品牌背书

Final Form 的独特优势

  • 框架无关设计,可在 React/Vue/Web Components 间共享表单逻辑
  • 订阅模式提供了最细粒度的渲染控制能力
  • 从 Redux Form 迁移最自然的路径
  • 模块化扩展设计,按需引入不增加冗余

Final Form 的明显劣势

  • 无内置 Schema 验证集成(Yup/Zod 需手动封装适配函数)
  • 单人维护,社区对可持续性存在担忧
  • 生态规模远小于 React Hook Form
  • 新项目采用率持续下降

最佳实践

生产环境建议

  1. 封装验证适配层:由于缺少 Schema 验证适配器,建议自行封装 Yup/Zod → Final Form validate 的转换函数:
// 封装 Zod Schema 为 Final Form validate 函数
import { z } from 'zod'
 
function zodToValidate(schema) {
  return async (values) => {
    try {
      await schema.parseAsync(values)
      return {}
    } catch (err) {
      if (err instanceof z.ZodError) {
        const errors = {}
        err.errors.forEach((issue) => {
          const path = issue.path.join('.')
          errors[path] = issue.message
        })
        return errors
      }
      return {}
    }
  }
}
 
// 使用
const schema = z.object({
  name: z.string().min(1, '姓名不能为空'),
  email: z.string().email('邮箱格式不正确'),
})
 
<Form onSubmit={onSubmit} validate={zodToValidate(schema)}>
  {/* ... */}
</Form>
  1. Subscription 最小化:为 &lt;Field&gt; 配置最小订阅范围
<Field
  name="email"
  subscription={{ value: true, error: true, touched: true }}
  component={TextInput}
/>
  1. 数组字段使用 Mutators
import arrayMutators from 'final-form-arrays'
import { FieldArray } from 'react-final-form-arrays'
 
<Form
  onSubmit={onSubmit}
  mutators={{ ...arrayMutators }}
  render={({ form }) => (
    <FieldArray name="items">
      {({ fields }) => (
        <div>
          {fields.map((name, index) => (
            <Field key={name} name={name} component="input" />
          ))}
          <button type="button" onClick={() => form.mutators.push('items', '')}>
            添加
          </button>
        </div>
      )}
    </FieldArray>
  )}
/>
  1. 多步骤表单:使用 ignoreUnregister(v5.0.1+)保留已取消注册字段的数据
<Form
  onSubmit={onSubmit}
  subscription={{ values: true }}
  // v5.0.1 新增:取消注册的字段跳过验证和提交检查
>
  {({ form }) => (
    // 步骤切换时,前一步骤的字段 unmount 但数据保留
  )}
</Form>

常见陷阱

  • ❌ 忘记为 &lt;Field&gt; 配置 subscription,导致默认订阅所有状态变化,丧失性能优势
  • ❌ 提交时忘记处理异步验证的 Promise,导致提交竞态条件
  • ❌ 数组字段不使用 final-form-arrays mutator,手动操作数组导致状态不同步
  • ❌ 在 validate 函数中执行昂贵计算,每次输入都触发性能问题
  • ❌ 未处理 initialValues 异步加载时的表单状态竞态(配合 keepDirtyOnReinitialize 使用)

推荐模式

// 推荐:封装可复用的表单组件
function AppForm({ onSubmit, validate, children, initialValues }) {
  return (
    <Form
      onSubmit={onSubmit}
      validate={validate}
      initialValues={initialValues}
      render={({ handleSubmit, submitting, hasValidationErrors }) => (
        <form onSubmit={handleSubmit}>
          {children}
          <button type="submit" disabled={submitting}>
            {submitting ? '提交中...' : '提交'}
          </button>
          {hasValidationErrors && <p className="error">请修正表单错误</p>}
        </form>
      )}
    />
  )
}

技术局限与边界

已知限制

  • 无 Schema 验证集成:不支持 validationSchema 或 resolvers 模式,所有验证逻辑必须手写函数或自行封装适配器
  • 单人维护风险:Erik Rasmussen 是唯一维护者,无核心团队或组织背书,长期可持续性存疑
  • 社区弃用呼声:2025 年 3 月出现正式的弃用请求 issue(#1045),虽未官方采纳但反映社区信心不足
  • 文档和示例陈旧:部分示例仍基于 React 17,新 API(如 ignoreUnregister)文档更新缓慢
  • 第三方 UI 集成少:相比 React Hook Form 丰富的 Controller 集成生态,Final Form 的 UI 封装选择有限(主要是 mui-rff)
  • TypeScript 迁移刚完成:v5.0 才从 Flow 迁移到 TypeScript,早期类型定义可能不够完善

不适用场景

  • 新项目默认选择:2026 年新建 React 项目,React Hook Form 是更稳妥的选择,生态更大、社区更活跃
  • 需要 Schema 验证集成:如果项目重度依赖 Yup/Zod 等 Schema 库,Final Form 需要自行封装适配层,不如 React Hook Form 或 TanStack Form 方便
  • 极简表单:仅 1-2 个字段的简单表单,使用原生 HTML 或 React state 即可
  • 追求社区支持:遇到问题时需要快速获得社区帮助的场景,Final Form 的社区响应速度不如 React Hook Form

迁移注意事项

  • 从 Redux Form 迁移:Final Form 是 Redux Form 的自然演进,API 设计思路相似但去除了 Redux 依赖。核心变化是 Field 组件的 component 属性、subscription 概念和 mutators 机制
  • 迁移到 React Hook Form:API 概念差异较大,&lt;Field&gt; 组件模式 vs register 钩子模式,需要逐步重构
  • v4 → v5 迁移:v5.0 从 Flow 迁移到 TypeScript,作者声明无破坏性变更,但建议检查自定义 mutator 和装饰器的类型兼容性

学习资源

2026 年现状

最新版本

  • final-form 稳定版:v5.0.1(2026 年 5 月 5 日)
  • react-final-form 稳定版:v7.0.1(2026 年 5 月 5 日)
  • final-form-arrays:v4.0.1
  • react-final-form-arrays:v5.0.0

v5.0 重要变更(2025-2026)

  • Flow → TypeScript 迁移:整个代码库从 Flow 类型系统完整迁移到 TypeScript,提升类型安全性和开发体验
  • React 19 支持:react-final-form v7.0.0 添加 React 19 peer dependency
  • ignoreUnregister 选项(v5.0.1):允许取消注册的字段跳过验证和提交检查,解决多步骤表单的痛点
  • 大量 Bug 修复:异步验证竞态条件、rejected promise 无限循环、数组字段 dirty 追踪、小数/负数键处理等

发展趋势

  • 维护节奏放缓:相比 React Hook Form 的活跃迭代,Final Form 的版本更新频率较低,主要由 Erik Rasmussen 利用业余时间维护
  • 社区可持续性存疑:2025 年出现弃用请求讨论,虽被拒绝但反映社区对单人维护模式的担忧
  • 框架无关价值的演进:随着 TanStack Form 等新兴框架无关库的崛起,Final Form 的框架无关优势不再是独特卖点
  • TypeScript 迁移带来的改善:v5.0 的 TypeScript 迁移为代码质量和社区贡献降低了门槛

社区活跃度

  • GitHub:final-form 约 3,100 Stars;react-final-form 约 8,500 Stars
  • npm:final-form 约 60 万周下载量;react-final-form 约 50 万周下载量
  • Open Issues:约 87 个
  • PkgPulse 健康分:77/100(Good)
  • 维护者 Erik Rasmussen 仍在参与,2025 年 6 月发布了 TypeScript 迁移博客

竞争态势

2026 年表单库生态格局:

  • React Hook Form 稳居 React 表单首选,市场份额遥遥领先
  • TanStack Form 凭借框架无关 + Headless 设计快速增长,是 Final Form 最直接的竞争者
  • Conform 在 SSR/全栈场景中崛起,渐进增强理念吸引关注
  • Final Form 仍保持稳定的存量用户,但新项目采用率持续下降

Final Form 在 2026 年适合已有项目的维护和迭代,以及需要框架无关设计的特定场景。新项目如无特殊需求,建议优先考虑 React Hook Form 或 TanStack Form。