TanStack Form 与您之前使用过的大多数表单库不同。它专为大规模生产使用而设计,专注于类型安全、性能和组合,以提供无与伦比的开发者体验。
因此,我们围绕库的使用开发了一套理念,该理念重视可扩展性和长期开发者体验,而不是简短且可分享的代码片段。
这是一个遵循我们许多最佳实践的表单示例,它将使您在经过短暂的入门体验后,能够快速开发甚至高度复杂的表单
import React from 'react'
import ReactDOM from 'react-dom/client'
import { createFormHook, createFormHookContexts } from '@tanstack/react-form'
// Form components that pre-bind events from the form hook; check our "Form Composition" guide for more
import { TextField, NumberField, SubmitButton } from '~our-app/ui-library'
// We also support Valibot, ArkType, and any other standard schema library
import { z } from 'zod'
const { fieldContext, formContext } = createFormHookContexts()
// Allow us to bind components to the form to keep type safety but reduce production boilerplate
// Define this once to have a generator of consistent form instances throughout your app
const { useAppForm } = createFormHook({
fieldComponents: {
TextField,
NumberField,
},
formComponents: {
SubmitButton,
},
fieldContext,
formContext,
})
const PeoplePage = () => {
const form = useAppForm({
defaultValues: {
username: '',
age: 0,
},
validators: {
// Pass a schema or function to validate
onChange: z.object({
username: z.string(),
age: z.number().min(13),
}),
},
onSubmit: ({ value }) => {
// Do something with form data
alert(JSON.stringify(value, null, 2))
},
})
return (
<form
onSubmit={(e) => {
e.preventDefault()
form.handleSubmit()
}}
>
<h1>Personal Information</h1>
{/* Components are bound to `form` and `field` to ensure extreme type safety */}
{/* Use `form.AppField` to render a component bound to a single field */}
<form.AppField
name="username"
children={(field) => <field.TextField label="Full Name" />}
/>
{/* The "name" property will throw a TypeScript error if typo'd */}
<form.AppField
name="age"
children={(field) => <field.NumberField label="Age" />}
/>
{/* Components in `form.AppForm` have access to the form context */}
<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'
// Form components that pre-bind events from the form hook; check our "Form Composition" guide for more
import { TextField, NumberField, SubmitButton } from '~our-app/ui-library'
// We also support Valibot, ArkType, and any other standard schema library
import { z } from 'zod'
const { fieldContext, formContext } = createFormHookContexts()
// Allow us to bind components to the form to keep type safety but reduce production boilerplate
// Define this once to have a generator of consistent form instances throughout your app
const { useAppForm } = createFormHook({
fieldComponents: {
TextField,
NumberField,
},
formComponents: {
SubmitButton,
},
fieldContext,
formContext,
})
const PeoplePage = () => {
const form = useAppForm({
defaultValues: {
username: '',
age: 0,
},
validators: {
// Pass a schema or function to validate
onChange: z.object({
username: z.string(),
age: z.number().min(13),
}),
},
onSubmit: ({ value }) => {
// Do something with form data
alert(JSON.stringify(value, null, 2))
},
})
return (
<form
onSubmit={(e) => {
e.preventDefault()
form.handleSubmit()
}}
>
<h1>Personal Information</h1>
{/* Components are bound to `form` and `field` to ensure extreme type safety */}
{/* Use `form.AppField` to render a component bound to a single field */}
<form.AppField
name="username"
children={(field) => <field.TextField label="Full Name" />}
/>
{/* The "name" property will throw a TypeScript error if typo'd */}
<form.AppField
name="age"
children={(field) => <field.NumberField label="Age" />}
/>
{/* Components in `form.AppForm` have access to the form context */}
<form.AppForm>
<form.SubmitButton />
</form.AppForm>
</form>
)
}
const rootElement = document.getElementById('root')!
ReactDOM.createRoot(rootElement).render(<PeoplePage />)
虽然我们通常建议使用 createFormHook 以长期减少样板代码,但我们也支持使用 useForm 和 form.Field 来实现一次性组件和其他行为
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 }) => {
// Do something with form data
alert(JSON.stringify(value, null, 2))
},
})
return (
<form.Field
name="age"
validators={{
// We can choose between form-wide and field-specific validators
onChange: ({ value }) =>
value > 13 ? undefined : 'Must be 13 or older',
}}
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.errors.length ? (
<em>{field.state.meta.errors.join(',')}</em>
) : null}
</>
)}
/>
)
}
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 }) => {
// Do something with form data
alert(JSON.stringify(value, null, 2))
},
})
return (
<form.Field
name="age"
validators={{
// We can choose between form-wide and field-specific validators
onChange: ({ value }) =>
value > 13 ? undefined : 'Must be 13 or older',
}}
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.errors.length ? (
<em>{field.state.meta.errors.join(',')}</em>
) : null}
</>
)}
/>
)
}
const rootElement = document.getElementById('root')!
ReactDOM.createRoot(rootElement).render(<PeoplePage />)
useForm 中的所有属性都可以在 useAppForm 中使用,form.Field 中的所有属性都可以在 form.AppField 中使用。
您每周的 JavaScript 新闻。每周一免费发送给超过 10 万名开发者。