React Hook表单验证错误(附实例)

922 阅读4分钟

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

React Hook Form Validation Errors

一个例子

这个例子与之前的文章类似,我们有一个捕捉用户姓名的表单:

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>)}

Validation error

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中找不到一个合适的可用类型。

所以,我们现在在表单无效的时候,在提交按钮下面有一个验证摘要。

Validation error summary UI很难看,但你会明白的

🏃播放代码

结束语

React Hook Form让我们可以灵活地呈现错误。我们创建的通用验证摘要组件可以用于任何React Hook Form。