使用React Hook Form的主-细节表单的指南

792 阅读3分钟

在过去的几篇文章中,我们已经建立了一个表单来捕获一个名字、一个电子邮件地址和一个分数,并有一些合理的复杂验证规则。

在这篇文章中,我们将从一个人身上获取多个分数,并将我们的表单变成一个主-细节表单。我们将从我们在上一篇文章中实现的表单开始。

使用useFieldArray

我们将使用React Hook Form的useFieldArray 来帮助渲染和管理分数。所以,让我们导入这个:

import {
  useForm,
  useFieldArray} from "react-hook-form";

我们现在要捕捉一个以上的分数,所以,让我们把字段名改为scores,并把它改为数组:

type PersonScore = {
  name: string;
  email: string;
  scores: number[];};

useFieldArray 需要使用来自 的 对象,它是表单的控制器。所以,让我们把这个结构去掉。useForm control

const {
  register,
  handleSubmit,
  errors,
  control} = useForm<PersonScore>();

我们现在可以使用useFieldArray

const { fields, append, remove } = useFieldArray(
  {
    control,
    name: "scores"
  }
);

我们已经从useFieldArray 中解构了以下内容:

  • fields.这是一个数组,将帮助我们渲染每个分数字段
  • append.这是一个函数,将允许我们添加分数字段
  • remove.这是一个函数,将使我们能够删除分数字段。

确保至少有一个分数

我们想从一个分数字段开始。因此,让我们使用append 函数来向数组中添加一个分数:

if (fields.length === 0) {
  append({});
}

该函数接收一个包含各字段默认值的对象。我们没有默认值,所以我们传递了一个空对象。

渲染分数字段

让我们继续渲染分数字段:

{
  fields.map((score, index) => (
    <div key={score.id}>
      <div className="field">
        <label htmlFor={`scores[${index}]`}>
          Score{` ${index + 1}`}
        </label>
        <input
          type="number"
          id={`scores[${index}]`}
          name={`scores[${index}]`}
          ref={register({
            required: true,
            min: 0,
            max: 100,
            validate: isEven
          })}
        />
      </div>
    </div>
  ));
}

我们正在对包含所有分数的fields 数组进行映射。我们为每个分数渲染一个labelinput

注意,我们使用fields 数组中的项目的id 属性作为React组件的键。这是由useFieldArray 给我们的一个指南。

我们需要给字段score[0]score[1]score[2]......命名,以便useFieldArray 可以管理它们。

我们的验证规则与上一篇文章中的表单的实现保持一致。让我们渲染一下验证的错误信息:

{
  errors.scores &&
    errors.scores[index] &&
    errors.scores[index].type === "required" && (
      <div className="error">
        You must enter your score.
      </div>
    );
}
{
  errors.scores &&
    errors.scores[index] &&
    errors.scores[index].type === "min" && (
      <div className="error">
        You score must be at least 0
      </div>
    );
}
{
  errors.scores &&
    errors.scores[index] &&
    errors.scores[index].type === "max" && (
      <div className="error">
        Your score must be no more than 100
      </div>
    );
}
{
  errors.scores &&
    errors.scores[index] &&
    errors.scores[index].type === "validate" && (
      <div className="error">
        Your score must be and even number
      </div>
    );
}

请注意,scores 的错误现在是在一个数组中。除此以外,每个数组的结构与普通字段相同。

添加和删除分数字段的按钮

让我们添加一个按钮来添加一个分数字段:

<button
  className="add"
  onClick={(e: React.MouseEvent) => {
    e.preventDefault();
    append({});
  }}
>
  Add score
</button>

当按钮被点击时,我们从useFieldArray 中调用append 函数来添加一个新的分数。

请注意,我们已经调用了事件preventDefault 方法,以确保在按钮被按下时,表单不会被提交。

我们也来添加一个按钮来删除一个分数字段:

<button
  className="remove"
  onClick={(e: React.MouseEvent) => {
    e.preventDefault();
    remove(index);
  }}
>
  Remove
</button>

当按钮被点击时,我们调用useFieldArray 中的函数remove ,输入要删除的分数的索引。

就这样了。这个表格的工作版本可以在CodeSandbox上找到。

总结

关于React Hook Form的系列文章已经结束了,我们用它来实现一些复杂但常见的表单需求。React Hook Form是一个很好的表单库,使用简单,性能也很好--在实现你的下一个表单时,非常值得一试!