浏览文档目录
第 19 课 · 类型化表单

让字段、校验与提交共享同一类型

用 useForm、Field 与 Subscribe 建立受控表单,把校验时机、错误显示和异步提交状态写成显式契约。

TanStack Form入门25 分钟REV 01Markdown .md
完成后你将能够

能实现字段名可推导、错误时机明确且不会重复提交的 Issue 表单。

01

默认值决定表单的输入类型

useForm 从 defaultValues 推导字段路径和 onSubmit value。每个 Field 通过 field.state.value 读取值,并用 field.handleChange、field.handleBlur 推进状态。不要混用 React 本地状态、DOM defaultValue 和 Form 的受控值,否则会产生多个事实来源。

02

把校验时机与错误展示分开

onBlur 适合避免用户每输入一个字符就看到错误;onChange 适合即时约束。验证器返回 truthy 错误值表示失败,返回 undefined 表示通过。错误数组可以存在于 meta,但界面通常还应检查 isTouched,避免初次渲染就责备用户。

src/features/issues/IssueForm.tsxtsx
import { useForm } from '@tanstack/react-form'

export function IssueForm() {
  const form = useForm({
    defaultValues: { title: '', priority: 'medium' as 'low' | 'medium' | 'high' },
    onSubmit: async ({ value }) => { await createIssue(value) },
  })
  return <form onSubmit={(event) => { event.preventDefault(); form.handleSubmit() }}>
    <form.Field name="title" validators={{
      onBlur: ({ value }) => value.trim() ? undefined : 'Title is required',
    }}>{(field) => <label>Title<input name={field.name} value={field.state.value}
      onBlur={field.handleBlur} onChange={(event) => field.handleChange(event.target.value)} />
      {field.state.meta.isTouched && !field.state.meta.isValid
        ? <span role="alert">{field.state.meta.errors.join(', ')}</span> : null}
    </label>}</form.Field>
    <form.Subscribe selector={(state) => [state.canSubmit, state.isSubmitting]}>
      {([canSubmit, isSubmitting]) => <button type="submit"
        aria-disabled={!canSubmit || isSubmitting} disabled={isSubmitting}>
        {isSubmitting ? 'Saving…' : 'Create issue'}
      </button>}
    </form.Subscribe>
  </form>
}
03

提交状态不是服务端信任边界

原生 submit 事件必须 preventDefault 后调用 form.handleSubmit,验证通过才进入 onSubmit。isSubmitting 覆盖异步 onSubmit,可用于阻止重复动作并显示进度。但客户端类型和校验都可绕过;Server Function 或 Server Route 必须重新解析、鉴权并返回可区分的字段错误与系统错误。

实践

把本课变成可验证的能力

完成检查点

字段名、默认值、校验器和 onSubmit value 共享同一类型,错误只在明确的交互时机显示。

动手练习

建立包含 title 与 priority 的 Issue 表单:title 在 blur 后校验非空,提交期间显示状态且防止重复提交。

验证方法

测试空标题、有效提交、异步失败和快速双击;无效值不进入 onSubmit,pending 期间只有一个请求,服务端仍独立验证输入。

常见错误
  • 给 input 同时传 defaultValue 和受控 value。
  • 只信任浏览器校验结果,把原始 value 直接写入服务端。
SOURCE REFERENCES · CHECKED 2026-08-03https://tanstack.com/form/latest/docs/framework/react/quick-starthttps://tanstack.com/form/latest/docs/framework/react/guides/validationhttps://tanstack.com/form/latest/docs/framework/react/guides/submission-handling