快速上手

TanStack Form 与您以前使用过的大多数表单库不同。它专为大规模生产环境而设计,注重类型安全、性能和组合,以提供无与伦比的开发体验。

因此,我们围绕库的使用制定了一套理念,该理念重视可伸缩性和长期开发体验,而不是简短且易于共享的代码片段。

以下是一个遵循我们许多最佳实践的表单示例,它将使您在短暂的入门体验后能够快速开发甚至高复杂度的表单:

tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { createFormHook, createFormHookContexts } from '@tanstack/react-form'
// 表单组件,用于从表单钩子预绑定事件;有关更多信息,请查看我们的“表单组合”指南
import { TextField, NumberField, SubmitButton } from '~our-app/ui-library'
// 我们还支持 Valibot、ArkType 和任何其他标准模式库
import { z } from 'zod'

const { fieldContext, formContext } = createFormHookContexts()

// 允许我们将组件绑定到表单以保持类型安全,但减少生产样板代码
// 定义一次即可在整个应用程序中生成一致的表单实例
const { useAppForm } = createFormHook({
  fieldComponents: {
    TextField,
    NumberField,
  },
  formComponents: {
    SubmitButton,
  },
  fieldContext,
  formContext,
})

const PeoplePage = () => {
  const form = useAppForm({
    defaultValues: {
      username: '',
age: 0,
    },
    validators: {
      // 传递模式或函数进行校验
      onChange: z.object({
        username: z.string(),
        age: z.number().min(13),
      }),
    },
    onSubmit: ({ value }) => {
      // 处理表单数据
      alert(JSON.stringify(value, null, 2))
    },
  })

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault()
        form.handleSubmit()
      }}
    >
      <h1>个人信息</h1>
      {/* 组件绑定到 `form` 和 `field` 以确保极高的类型安全性 */}
      {/* 使用 `form.AppField` 渲染绑定到单个字段的组件 */}
      <form.AppField
        name="username"
        children={(field) => <field.TextField label="全名" />}
      />
      {/* 如果拼写错误,“name”属性将引发 TypeScript 错误 */}
      <form.AppField
        name="age"
        children={(field) => <field.NumberField label="年龄" />}
      />
      {/* `form.AppForm` 中的组件可以访问表单上下文 */}
      <form.AppForm>
        <form.SubmitButton />
      </form.AppForm>
    </form>
  )
}

const rootElement = document.getElementById('root')!
ReactDOM.createRoot(rootElement).render(<PeoplePage />)
import React from 'react'
import ReactDOM from 'react-dom/client'
import { createFormHook, createFormHookContexts } from '@tanstack/react-form'
// 表单组件,用于从表单钩子预绑定事件;有关更多信息,请查看我们的“表单组合”指南
import { TextField, NumberField, SubmitButton } from '~our-app/ui-library'
// 我们还支持 Valibot、ArkType 和任何其他标准模式库
import { z } from 'zod'

const { fieldContext, formContext } = createFormHookContexts()

// 允许我们将组件绑定到表单以保持类型安全,但减少生产样板代码
// 定义一次即可在整个应用程序中生成一致的表单实例
const { useAppForm } = createFormHook({
  fieldComponents: {
    TextField,
    NumberField,
  },
  formComponents: {
    SubmitButton,
  },
  fieldContext,
  formContext,
})

const PeoplePage = () => {
  const form = useAppForm({
    defaultValues: {
      username: '',
age: 0,
    },
    validators: {
      // 传递模式或函数进行校验
      onChange: z.object({
        username: z.string(),
        age: z.number().min(13),
      }),
    },
    onSubmit: ({ value }) => {
      // 处理表单数据
      alert(JSON.stringify(value, null, 2))
    },
  })

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault()
        form.handleSubmit()
      }}
    >
      <h1>个人信息</h1>
      {/* 组件绑定到 `form` 和 `field` 以确保极高的类型安全性 */}
      {/* 使用 `form.AppField` 渲染绑定到单个字段的组件 */}
      <form.AppField
        name="username"
        children={(field) => <field.TextField label="全名" />}
      />
      {/* 如果拼写错误,“name”属性将引发 TypeScript 错误 */}
      <form.AppField
        name="age"
        children={(field) => <field.NumberField label="年龄" />}
      />
      {/* `form.AppForm` 中的组件可以访问表单上下文 */}
      <form.AppForm>
        <form.SubmitButton />
      </form.AppForm>
    </form>
  )
}

const rootElement = document.getElementById('root')!
ReactDOM.createRoot(rootElement).render(<PeoplePage />)

虽然我们通常建议使用 createFormHook 来减少长期的样板代码,但我们也支持使用 useFormform.Field 的一次性组件和其他行为:

tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { useForm } from '@tanstack/react-form'

const PeoplePage = () => {
  const form = useForm({
    defaultValues: {
      username: '',
age: 0,
    },
    onSubmit: ({ value }) => {
      // 处理表单数据
      alert(JSON.stringify(value, null, 2))
    },
  })

  return (
    <form.Field
      name="age"
      validators={{
        // 我们可以选择表单范围或字段特定的校验器
        onChange: ({ value }) =>
          value > 13 ? undefined : '必须年满 13 岁',
      }}
      children={(field) => (
        <>
          <input
            name={field.name}
            value={field.state.value}
            onBlur={field.handleBlur}
            type="number"
            onChange={(e) => field.handleChange(e.target.valueAsNumber)}
          />
          {!field.state.meta.isValid && (
            <em>{field.state.meta.errors.join(',')}</em>
          )}
        </>
      )}
    />
  )
}

const rootElement = document.getElementById('root')!
ReactDOM.createRoot(rootElement).render(<PeoplePage />)
import React from 'react'
import ReactDOM from 'react-dom/client'
import { useForm } from '@tanstack/react-form'

const PeoplePage = () => {
  const form = useForm({
    defaultValues: {
      username: '',
age: 0,
    },
    onSubmit: ({ value }) => {
      // 处理表单数据
      alert(JSON.stringify(value, null, 2))
    },
  })

  return (
    <form.Field
      name="age"
      validators={{
        // 我们可以选择表单范围或字段特定的校验器
        onChange: ({ value }) =>
          value > 13 ? undefined : '必须年满 13 岁',
      }}
      children={(field) => (
        <>
          <input
            name={field.name}
            value={field.state.value}
            onBlur={field.handleBlur}
            type="number"
            onChange={(e) => field.handleChange(e.target.valueAsNumber)}
          />
          {!field.state.meta.isValid && (
            <em>{field.state.meta.errors.join(',')}</em>
          )}
        </>
      )}
    />
  )
}

const rootElement = document.getElementById('root')!
ReactDOM.createRoot(rootElement).render(<PeoplePage />)

useForm 的所有属性都可以在 useAppForm 中使用,form.Field 的所有属性都可以在 form.AppField 中使用。