TanStack Form 在您可以从验证器返回的错误值类型方面提供了完全的灵活性。字符串错误是最常见且易于使用的,但该库允许您从验证器返回任何类型的值。
作为一般规则,任何真值都被视为错误,并将表单或字段标记为无效,而假值(false、undefined、null 等)意味着没有错误,表单或字段是有效的。
<form.Field
name="username"
validators={{
onChange: ({ value }) =>
value.length < 3 ? '用户名必须至少包含 3 个字符' : undefined,
}}
/>
<form.Field
name="username"
validators={{
onChange: ({ value }) =>
value.length < 3 ? '用户名必须至少包含 3 个字符' : undefined,
}}
/>
对于影响多个字段的表单级验证:
const form = useForm({
defaultValues: {
username: '',
email: '',
},
validators: {
onChange: ({ value }) => {
return {
fields: {
username:
value.username.length < 3 ? '用户名太短' : undefined,
email: !value.email.includes('@') ? '无效的电子邮件' : undefined,
},
}
},
},
})
const form = useForm({
defaultValues: {
username: '',
email: '',
},
validators: {
onChange: ({ value }) => {
return {
fields: {
username:
value.username.length < 3 ? '用户名太短' : undefined,
email: !value.email.includes('@') ? '无效的电子邮件' : undefined,
},
}
},
},
})
字符串错误是最常见的类型,可以轻松在您的 UI 中显示:
{
field.state.meta.errors.map((error, i) => (
<div key={i} className="error">
{error}
</div>
))
}
{
field.state.meta.errors.map((error, i) => (
<div key={i} className="error">
{error}
</div>
))
}
用于表示数量、阈值或大小:
<form.Field
name="age"
validators={{
onChange: ({ value }) => (value < 18 ? 18 - value : undefined),
}}
/>
<form.Field
name="age"
validators={{
onChange: ({ value }) => (value < 18 ? 18 - value : undefined),
}}
/>
Display in UI:
{
/* TypeScript knows the error is a number based on your validator */
}
;<div className="error">
您还需要 {field.state.meta.errors[0]} 年才能符合条件
</div>
{
/* TypeScript knows the error is a number based on your validator */
}
;<div className="error">
您还需要 {field.state.meta.errors[0]} 年才能符合条件
</div>
用于指示错误状态的简��标志:
<form.Field
name="accepted"
validators={{
onChange: ({ value }) => (!value ? true : undefined),
}}
/>
<form.Field
name="accepted"
validators={{
onChange: ({ value }) => (!value ? true : undefined),
}}
/>
Display in UI:
{
field.state.meta.errors[0] === true && (
<div className="error">您必须接受条款</div>
)
}
{
field.state.meta.errors[0] === true && (
<div className="error">您必须接受条款</div>
)
}
具有多个属性的丰富错误对象:
<form.Field
name="email"
validators={{
onChange: ({ value }) => {
if (!value.includes('@')) {
return {
message: '无效的电子邮件格式',
severity: 'error',
code: 1001,
}
}
return undefined
},
}}
/>
<form.Field
name="email"
validators={{
onChange: ({ value }) => {
if (!value.includes('@')) {
return {
message: '无效的电子邮件格式',
severity: 'error',
code: 1001,
}
}
return undefined
},
}}
/>
Display in UI:
{
typeof field.state.meta.errors[0] === 'object' && (
<div className={`error ${field.state.meta.errors[0].severity}`}>
{field.state.meta.errors[0].message}
<small> (Code: {field.state.meta.errors[0].code})</small>
</div>
)
}
{
typeof field.state.meta.errors[0] === 'object' && (
<div className={`error ${field.state.meta.errors[0].severity}`}>
{field.state.meta.errors[0].message}
<small> (Code: {field.state.meta.errors[0].code})</small>
</div>
)
}
在上面的示例中,这取决于您想要显示的事件错误。
单个字段的多个错误消息:
<form.Field
name="password"
validators={{
onChange: ({ value }) => {
const errors = []
if (value.length < 8) errors.push('密码太短')
if (!/[A-Z]/.test(value)) errors.push('缺少大写字母')
if (!/[0-9]/.test(value)) errors.push('缺少数字')
return errors.length ? errors : undefined
},
}}
/>
<form.Field
name="password"
validators={{
onChange: ({ value }) => {
const errors = []
if (value.length < 8) errors.push('密码太短')
if (!/[A-Z]/.test(value)) errors.push('缺少大写字母')
if (!/[0-9]/.test(value)) errors.push('缺少数字')
return errors.length ? errors : undefined
},
}}
/>
Display in UI:
{
Array.isArray(field.state.meta.errors) && (
<ul className="error-list">
{field.state.meta.errors.map((err, i) => (
<li key={i}>{err}</li>
))}
</ul>
)
}
{
Array.isArray(field.state.meta.errors) && (
<ul className="error-list">
{field.state.meta.errors.map((err, i) => (
<li key={i}>{err}</li>
))}
</ul>
)
}
By default, TanStack Form flattens errors from all validation sources (onChange, onBlur, onSubmit) into a single errors array. The disableErrorFlat prop preserves the error sources:
<form.Field
name="email"
disableErrorFlat
validators={{
onChange: ({ value }) =>
!value.includes('@') ? 'Invalid email format' : undefined,
onBlur: ({ value }) =>
!value.endsWith('.com') ? 'Only .com domains allowed' : undefined,
onSubmit: ({ value }) => (value.length < 5 ? 'Email too short' : undefined),
}}
/>
<form.Field
name="email"
disableErrorFlat
validators={{
onChange: ({ value }) =>
!value.includes('@') ? 'Invalid email format' : undefined,
onBlur: ({ value }) =>
!value.endsWith('.com') ? 'Only .com domains allowed' : undefined,
onSubmit: ({ value }) => (value.length < 5 ? 'Email too short' : undefined),
}}
/>
Without disableErrorFlat, all errors would be combined into field.state.meta.errors. With it, you can access errors by their source:
{
field.state.meta.errorMap.onChange && (
<div className="real-time-error">{field.state.meta.errorMap.onChange}</div>
)
}
{
field.state.meta.errorMap.onBlur && (
<div className="blur-feedback">{field.state.meta.errorMap.onBlur}</div>
)
}
{
field.state.meta.errorMap.onSubmit && (
<div className="submit-error">{field.state.meta.errorMap.onSubmit}</div>
)
}
{
field.state.meta.errorMap.onChange && (
<div className="real-time-error">{field.state.meta.errorMap.onChange}</div>
)
}
{
field.state.meta.errorMap.onBlur && (
<div className="blur-feedback">{field.state.meta.errorMap.onBlur}</div>
)
}
{
field.state.meta.errorMap.onSubmit && (
<div className="submit-error">{field.state.meta.errorMap.onSubmit}</div>
)
}
This is useful for:
TanStack Form provides strong type safety for error handling. Each key in the errorMap has exactly the type returned by its corresponding validator, while the errors array contains a union type of all the possible error values from all validators:
<form.Field
name="password"
validators={{
onChange: ({ value }) => {
// This returns a string or undefined
return value.length < 8 ? 'Too short' : undefined
},
onBlur: ({ value }) => {
// 这返回一个对象或 undefined
if (!/[A-Z]/.test(value)) {
return { message: '缺少大写字母', level: 'warning' }
}
return undefined
},
}}
children={(field) => {
// TypeScript 知道 errors[0] 可以是 string | { message: string, level: string } | undefined
const error = field.state.meta.errors[0]
// 类型安全的错误处理
if (typeof error === 'string') {
return <div className="string-error">{error}</div>
} else if (error && typeof error === 'object') {
return <div className={error.level}>{error.message}</div>
}
return null
}}
/>
<form.Field
name="password"
validators={{
onChange: ({ value }) => {
// This returns a string or undefined
return value.length < 8 ? 'Too short' : undefined
},
onBlur: ({ value }) => {
// 这返回一个对象或 undefined
if (!/[A-Z]/.test(value)) {
return { message: '缺少大写字母', level: 'warning' }
}
return undefined
},
}}
children={(field) => {
// TypeScript 知道 errors[0] 可以是 string | { message: string, level: string } | undefined
const error = field.state.meta.errors[0]
// 类型安全的错误处理
if (typeof error === 'string') {
return <div className="string-error">{error}</div>
} else if (error && typeof error === 'object') {
return <div className={error.level}>{error.message}</div>
}
return null
}}
/>
errorMap 属性也是完全类型化的,与您的验证函数的返回类型匹配:
// With disableErrorFlat
<form.Field
name="email"
disableErrorFlat
validators={{
onChange: ({ value }): string | undefined =>
!value.includes("@") ? "无效的电子邮件" : undefined,
onBlur: ({ value }): { code: number, message: string } | undefined =>
!value.endsWith(".com") ? { code: 100, message: "错误的域名" } : undefined
}}
children={(field) => {
// TypeScript 知道每个错误源的确切类型
const onChangeError: string | undefined = field.state.meta.errorMap.onChange;
const onBlurError: { code: number, message: string } | undefined = field.state.meta.errorMap.onBlur;
return (/* ... */);
}}
/>
// With disableErrorFlat
<form.Field
name="email"
disableErrorFlat
validators={{
onChange: ({ value }): string | undefined =>
!value.includes("@") ? "无效的电子邮件" : undefined,
onBlur: ({ value }): { code: number, message: string } | undefined =>
!value.endsWith(".com") ? { code: 100, message: "错误的域名" } : undefined
}}
children={(field) => {
// TypeScript 知道每个错误源的确切类型
const onChangeError: string | undefined = field.state.meta.errorMap.onChange;
const onBlurError: { code: number, message: string } | undefined = field.state.meta.errorMap.onBlur;
return (/* ... */);
}}
/>
这种类型安全有助于在编译时而不是运行时捕获错误,使您的代码更可靠和可维护。