TanStack Form 在您可以从验证器返回的错误值类型方面提供了完全的灵活性。字符串错误是最常见且易于使用的,但该库允许您从验证器返回任何类型的值。
作为一般规则,任何真值都被视为错误,并将表单或字段标记为无效,而假值(false、undefined、null 等)表示没有错误,表单或字段是有效的。
<form.Field
name="username"
validators={{
onChange: ({ value }) =>
value.length < 3 ? 'Username must be at least 3 characters' : undefined,
}}
/>
<form.Field
name="username"
validators={{
onChange: ({ value }) =>
value.length < 3 ? 'Username must be at least 3 characters' : undefined,
}}
/>
对于影响多个字段的表单级别验证
const form = useForm({
defaultValues: {
username: '',
email: '',
},
validators: {
onChange: ({ value }) => {
return {
fields: {
username:
value.username.length < 3 ? 'Username too short' : undefined,
email: !value.email.includes('@') ? 'Invalid email' : undefined,
},
}
},
},
})
const form = useForm({
defaultValues: {
username: '',
email: '',
},
validators: {
onChange: ({ value }) => {
return {
fields: {
username:
value.username.length < 3 ? 'Username too short' : undefined,
email: !value.email.includes('@') ? 'Invalid email' : 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),
}}
/>
在 UI 中显示
{
/* TypeScript knows the error is a number based on your validator */
}
;<div className="error">
You need {field.state.meta.errors[0]} more years to be eligible
</div>
{
/* TypeScript knows the error is a number based on your validator */
}
;<div className="error">
You need {field.state.meta.errors[0]} more years to be eligible
</div>
指示错误状态的简单标志
<form.Field
name="accepted"
validators={{
onChange: ({ value }) => (!value ? true : undefined),
}}
/>
<form.Field
name="accepted"
validators={{
onChange: ({ value }) => (!value ? true : undefined),
}}
/>
在 UI 中显示
{
field.state.meta.errors[0] === true && (
<div className="error">You must accept the terms</div>
)
}
{
field.state.meta.errors[0] === true && (
<div className="error">You must accept the terms</div>
)
}
具有多个属性的丰富错误对象
<form.Field
name="email"
validators={{
onChange: ({ value }) => {
if (!value.includes('@')) {
return {
message: 'Invalid email format',
severity: 'error',
code: 1001,
}
}
return undefined
},
}}
/>
<form.Field
name="email"
validators={{
onChange: ({ value }) => {
if (!value.includes('@')) {
return {
message: 'Invalid email format',
severity: 'error',
code: 1001,
}
}
return undefined
},
}}
/>
在 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('Password too short')
if (!/[A-Z]/.test(value)) errors.push('Missing uppercase letter')
if (!/[0-9]/.test(value)) errors.push('Missing number')
return errors.length ? errors : undefined
},
}}
/>
<form.Field
name="password"
validators={{
onChange: ({ value }) => {
const errors = []
if (value.length < 8) errors.push('Password too short')
if (!/[A-Z]/.test(value)) errors.push('Missing uppercase letter')
if (!/[0-9]/.test(value)) errors.push('Missing number')
return errors.length ? errors : undefined
},
}}
/>
在 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>
)
}
默认情况下,TanStack Form 将来自所有验证源(onChange、onBlur、onSubmit)的错误展平为单个 errors 数组。disableErrorFlat prop 保留了错误来源
<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),
}}
/>
如果没有 disableErrorFlat,所有错误都将合并到 field.state.meta.errors 中。有了它,您可以按来源访问错误
{
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>
)
}
这对于以下情况很有用
errors
和 errorMap
的类型安全TanStack Form 为错误处理提供了强大的类型安全性。errorMap
中的每个键都具有与其对应的验证器返回的类型完全相同的类型,而 errors
数组包含来自所有验证器的所有可能错误值的联合类型
<form.Field
name="password"
validators={{
onChange: ({ value }) => {
// This returns a string or undefined
return value.length < 8 ? 'Too short' : undefined
},
onBlur: ({ value }) => {
// This returns an object or undefined
if (!/[A-Z]/.test(value)) {
return { message: 'Missing uppercase', level: 'warning' }
}
return undefined
},
}}
children={(field) => {
// TypeScript knows that errors[0] can be string | { message: string, level: string } | undefined
const error = field.state.meta.errors[0]
// Type-safe error handling
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 }) => {
// This returns an object or undefined
if (!/[A-Z]/.test(value)) {
return { message: 'Missing uppercase', level: 'warning' }
}
return undefined
},
}}
children={(field) => {
// TypeScript knows that errors[0] can be string | { message: string, level: string } | undefined
const error = field.state.meta.errors[0]
// Type-safe error handling
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("@") ? "Invalid email" : undefined,
onBlur: ({ value }): { code: number, message: string } | undefined =>
!value.endsWith(".com") ? { code: 100, message: "Wrong domain" } : undefined
}}
children={(field) => {
// TypeScript knows the exact type of each error source
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("@") ? "Invalid email" : undefined,
onBlur: ({ value }): { code: number, message: string } | undefined =>
!value.endsWith(".com") ? { code: 100, message: "Wrong domain" } : undefined
}}
children={(field) => {
// TypeScript knows the exact type of each error source
const onChangeError: string | undefined = field.state.meta.errorMap.onChange;
const onBlurError: { code: number, message: string } | undefined = field.state.meta.errorMap.onBlur;
return (/* ... */);
}}
/>
这种类型安全有助于在编译时而不是运行时捕获错误,从而使您的代码更可靠且更易于维护。
您的每周 JavaScript 新闻。每周一免费发送给超过 100,000 名开发者。