当验证检查失败时,显示信息性的消息是至关重要的,这样用户就可以采取适当的行动。在这篇文章中,我们看一下在React Hook Form中指定和输出这些验证错误信息的不同方式。我们还将介绍如何创建一个通用的验证错误摘要组件:

一个例子
这个例子与之前的文章类似,我们有一个捕捉用户姓名的表单:
type FormData = {
name: string;
};
export default function App() {
const { register, handleSubmit } = useForm<FormData>();
const submitForm = (data: FormData) => {
console.log("Submission", data);
};
return (
<div className="app">
<form onSubmit={handleSubmit(submitForm)}>
<div>
<input
ref={register({
required: true,
minLength: 2
})}
type="text"
name="name"
placeholder="Enter your name"
/>
</div>
</form>
</div>
);
}
这一次,表单有两条验证规则,以确保名字被填入,并且至少包含两个字符。
渲染一个字段的验证错误
验证错误被存储在 errors对象中:
const {
register,
handleSubmit,
errors,} = useForm<FormData>();
errors 对象的格式如下:
{
<fieldName>: {
type: <ruleName>
},
...
}
我们表单的一个例子errors 对象是:
{
name: {
type: "required"
}
}
可以有多个字段出现错误。如果一个特定的字段包含多个验证规则,那么它可以有不同的错误。如果一个字段或规则上没有验证错误,它就不存在于errors 对象中。
所以,我们可以在名称输入后呈现错误信息,如下所示。
<input ... />
{errors.name && errors.name.type === "required" && ( <div className="error">You must enter your name</div>)}{errors.name && errors.name.type === "minLength" && ( <div className="error">Your name must be at least 2 characters</div>)}

在register 函数中指定错误信息
另一种方法是在register 函数中指定错误信息,如下所示:
<input
ref={register({
required: { value: true, message: "You must enter your name" }, minLength: { value: 2, message: "Your name must be at least 2 characters" } })}
type="text"
name="name"
placeholder="Enter your name"
/>
然后,验证错误信息在errors 对象中的一个message 属性中可用,如下所示:
{
name: {
type: "required",
message: "You must enter your name" }
}
因此,我们可以将错误信息的呈现方式改为如下:
<input ... />
{errors.name && ( <div className="error">{errors.name.message}</div>)}
如果错误信息是可配置的,并从服务器获取并推送到表单中,这就很好。
使用ErrorMessage 组件
如果我们有一个用于验证错误的通用组件,可以说会更干净。幸运的是,这已经存在于React Hook Form的@hookform/error-message 包中。该组件被称为 ErrorMessage,我们可以按以下方式使用它:
<input
name="name"
...
/>
<ErrorMessage errors={errors} name="name" />
因此,我们将所有的错误传入ErrorMessage ,并使用name 属性告诉它要显示哪个字段的错误。
这个组件默认只是渲染一个字符串。我们可以使用as 属性告诉它将错误信息放在哪个元素中:
<ErrorMessage
errors={errors}
name="name"
as="span"/>
因此,这将在一个span 元素中呈现错误信息。
我们也可以使用as ,在我们自己的组件中渲染信息:
<ErrorMessage
errors={errors}
name="name"
as={<ErrorMessageContainer />}/>
然后我们可以在容器组件中指定样式:
type ErrorMessageContainerProps = {
children?: React.ReactNode;
};
const ErrorMessageContainer = ({ children }: ErrorMessageContainerProps) => (
<span className="error">{children}</span>
);
很好!
渲染一个验证错误摘要
如果我们想在提交按钮后把所有的错误都呈现出来呢?这对大型表单很有用,因为当提交按钮被按下时,字段可能会离开屏幕的顶部。
让我们为此建立一个通用组件,叫做ErrorSummary 。我们将在提交按钮下使用这个组件,具体如下:
<div>
<button type="submit">Submit</button>
</div>
<ErrorSummary errors={errors} />
首先,我们将在我们的表单中添加一个年龄字段,给通用组件一个很好的测试:
type FormData = {
name: string;
age: number;};
export default function App() {
...
return (
<div className="app">
<form onSubmit={handleSubmit(submitForm)}>
...
<div> <input ref={register({ required: { value: true, message: "You must enter your age" }, min: { value: 30, message: "You must be at least 30" } })} type="number" name="age" placeholder="Enter your age" /> <ErrorMessage errors={errors} name="age" as={<ErrorMessageContainer />} /> </div> ...
</form>
</div>
);
}
我们仍然在每个字段后渲染错误。我们的要求是在提交按钮后再次呈现所有的错误。
让我们开始实现ErrorSummary :
type ErrorSummaryProps<T> = {
errors: FieldErrors<T>;
};
function ErrorSummary<T>({
errors,
}: ErrorSummaryProps<T>) {}
该组件包含一个errors 道具,它将包含所有的错误。FieldErrors 是一个类型,代表React Hook Form的errors 对象。
当没有错误要输出时,我们将返回null :
function ErrorSummary<T>({
errors,
}: ErrorSummaryProps<T>) {
if (Object.keys(errors).length === 0) { return null; }}
然后我们可以迭代并渲染每个错误:
function ErrorSummary<T>({ errors }: ErrorsProps<T>) {
if (Object.keys(errors).length === 0) {
return null;
}
return ( <div className="error-summary"> {Object.keys(errors).map((fieldName) => ( <ErrorMessage errors={errors} name={fieldName as any} as="div" key={fieldName} /> ))} </div> );}
我们使用ErrorMessage 组件来渲染每个错误。目前,我把fieldName 断言为any ,因为我在React Hook Form中找不到一个合适的可用类型。
所以,我们现在在表单无效的时候,在提交按钮下面有一个验证摘要。
UI很难看,但你会明白的
🏃播放代码
结束语
React Hook Form让我们可以灵活地呈现错误。我们创建的通用验证摘要组件可以用于任何React Hook Form。