TanStack Form:构建类型安全的复杂表单

前端开发

为什么选择 TanStack Form?

市面上已经有了 React Hook Form 和 Formik,为什么还需要 TanStack Form?

  1. 极致的类型安全:从定义字段到提交数据,全程 TypeScript 推断,几乎不需要手动定义类型。
  2. 框架无关:虽然本文以 React 为例,但 TanStack Form 的核心逻辑可以运行在 Vue、Solid 甚至原生 JS 中。
  3. Headless 设计:它只负责逻辑,不负责 UI。你可以完全掌控表单的渲染方式,轻松集成 shadcn/ui 或 Material UI。

快速上手

安装依赖:

npm install @tanstack/react-form zod

这里我们配合 Zod 进行校验(可选)。

1. 定义表单

import { useForm } from '@tanstack/react-form';

function MyForm() {
  const form = useForm({
    defaultValues: {
      firstName: '',
      age: 0,
    },
    onSubmit: async ({ value }) => {
      // value 是类型安全的
      console.log(value);
    },
  });

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        e.stopPropagation();
        form.handleSubmit();
      }}
    >
      {/* 字段渲染逻辑 */}
    </form>
  );
}

2. 绑定字段

使用 form.Field 组件来绑定具体的输入框:

<form.Field
  name="firstName"
  validators={{
    onChange: ({ value }) =>
      !value ? '名字不能为空' : undefined,
  }}
  children={(field) => (
    <div>
      <label>First Name:</label>
      <input
        name={field.name}
        value={field.state.value}
        onBlur={field.handleBlur}
        onChange={(e) => field.handleChange(e.target.value)}
      />
      {field.state.meta.errors ? (
        <em role="alert">{field.state.meta.errors.join(', ')}</em>
      ) : null}
    </div>
  )}
/>

注意,这里使用了 Render Prop 模式。field 对象包含了当前字段的所有状态(value, errors, isTouched 等)和操作方法(handleChange, handleBlur)。

深度功能

复杂嵌套对象与数组

TanStack Form 对深层嵌套对象和数组的支持非常完美。你可以轻松处理动态增删的表单项,且不会丢失类型提示。

细粒度订阅

性能是 TanStack Form 的另一大亮点。它允许组件只订阅特定的状态变化。例如,你可以让某个组件只在 isValid 变化时重新渲染,而忽略 value 的变化。

结语

TanStack Form 或许有一定的学习曲线,但一旦上手,你会发现它处理复杂表单逻辑时的从容与优雅。对于追求长期可维护性和类型安全的大型项目,TanStack Form 是一个非常值得投入的选择。