🌱 拆解核心概念
✅ useForm
useForm
是整个表单的控制中心,它定义了默认值、提交行为、验证逻辑等:
tsx
const form = useForm({
defaultValues: {
firstName: '',
lastName: '',
},
onSubmit: async ({ value }) => {
console.log(value)
},
})
你会获得一个 form
实例,拥有 .Field
、.handleSubmit()
、.Subscribe()
等强大方法。
✅ form.Field
tsx
<form.Field
name="firstName"
children={(field) => (
<>
<label htmlFor={field.name}>First Name:</label>
<input
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
</>
)}
/>
你无需手动绑定 value
和 onChange
------ field
已为你封装好了完整的输入控件状态与行为,包含:
-
field.state.value
: 当前值 -
field.handleChange
: 更新值 -
field.handleBlur
: 聚焦失效处理 -
field.name
: 自动生成name
属性
✅ form.Subscribe
订阅表单状态变化,比如是否可提交、是否正在提交等:
tsx
<form.Subscribe
selector={(state) => [state.canSubmit, state.isSubmitting]}
children={([canSubmit, isSubmitting]) => (
<>
<button type="submit" disabled={!canSubmit}>
{isSubmitting ? '...' : 'Submit'}
</button>
<button
type="reset"
onClick={(e) => {
// Avoid unexpected resets of form elements (especially <select> elements)
e.preventDefault()
form.reset()
}}
>
Reset
</button>
</>
)}
/>

官方代码地址🔗: @tanStack/react-form
🧠 进阶:添加表单验证逻辑
写完最基础的表单后,很多人心里都有同一个声音:
"没有验证功能,它顶多只是个表单状态机罢了!"
别急,验证在 @tanStack/react-form
中不仅有,而且功能极其灵活、写法非常优雅。来看这一段👇:
tsx
<form.Field
name="firstName"
validators={{
onChange: ({ value }) =>
!value
? 'A first name is required'
: value.length < 3
? 'First name must be at least 3 characters'
: undefined,
onChangeAsyncDebounceMs: 500,
onChangeAsync: async ({ value }) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return (
value.includes('error') && 'No "error" allowed in first name'
);
},
}}
children={(field) => (
<>
<label htmlFor={field.name}>First Name:</label>
<input
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
)}
/>
✅ 支持同步和异步校验
你可以同时配置:
-
onChange
:同步验证(即时反馈) -
onChangeAsync
:异步验证(如:服务器检查用户名是否存在) -
onChangeAsyncDebounceMs
:防抖,防止输入瞬间触发 N 次请求
✅ 错误信息展示组件 FieldInfo
tsx
function FieldInfo({ field }: { field: AnyFieldApi }) {
return (
<>
{field.state.meta.isTouched && !field.state.meta.isValid ? (
<em>{field.state.meta.errors.join(',')}</em>
) : null}
{field.state.meta.isValidating ? 'Validating...' : null}
</>
);
}
🌟 小提示:
field.state.meta
包含了验证相关的各种状态标志
-
isTouched
:是否被用户操作过 -
isValid
:是否通过验证 -
isValidating
:是否正在验证中 -
errors
:错误信息列表(数组)
这样一来,我们可以精准控制什么时候展示错误、是否显示 loading
验证提示,而不是"盲目红框提示"。
✅ 校验逻辑完全可控
校验逻辑可以使用熟悉的 JS
函数,比如这个 async
校验,就像我们真实业务中可能碰到的一样:
tsx
onChangeAsync: async ({ value }) => {
await new Promise((r) => setTimeout(r, 1000));
return value.includes('error') && 'No "error" allowed';
}

官方代码地址🔗: @tanStack/react-form
🌐 与 Zod 搭配使用
Zod 是一个强类型、链式语法的对象验证库,天然与 TypeScript 和 React 配合得天衣无缝。
🎯 示例:用 Zod
校验 age
字段
我们要验证用户的年龄必须 ≥ 13
岁,来看示例:
tsx
import { z } from 'zod'
const userSchema = z.object({
age: z.number().gte(13, 'You must be 13 to make an account'),
})
function App() {
const form = useForm({
defaultValues: {
age: 0,
},
validators: {
onChange: userSchema, // 传入 Zod schema
},
})
return //....
}
🔍 Zod 校验发生在哪里?
你只需要将 schema
传给 validators.onChange
,其余的事情 @tanStack/react-form
全帮你搞定:
tsx
validators: {
onChange: userSchema,
}
-
userSchema
会自动校验所有字段 -
错误信息自动绑定到字段的
meta
中 -
配合
<FieldInfo />
显示错误信息轻轻松松
🔄 同时验证多个字段?
tsx
const schema = z.object({
firstName: z
.string()
.min(3, '[Zod] You must have a length of at least 3')
.startsWith('A', "[Zod] First name must start with 'A'"),
lastName: z.string().min(3, '[Zod] You must have a length of at least 3'),
})
然后直接作为 validators.onChange
传入:
tsx
useForm({
defaultValues: {
firstName: '',
lastName: '',
age: 0,
},
validators: {
onChange: userSchema,
},
})

官方代码地址🔗: @tanStack/react-form