我的编程空间,编程开发者的网络收藏夹
学习永远不晚

ReactHookForm优雅处理表单使用指南

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

ReactHookForm优雅处理表单使用指南

受控组件与非受控组件

受控组件

先说说受控组件,以 input 为例:

const [value,setValue] = useState('')
<input value={value} onChange={(e)=> setValue(e.target.value)} />

在上面的代码中,我们通过通过自己维护一个 state 来获取或更新 input 输入的值,以这种方式控制取值的 表单输入元素 就叫做 受控组件

非受控组件

那么什么是非受控组件呢?在 React 中,非受控组件是指表单元素的值由 DOM 节点直接处理,而不是由 React 组件来管理。如下例:

import React, { useRef } from 'react';
function UncontrolledForm() {
  const nameInputRef = useRef(null);
  const emailInputRef = useRef(null);
  const passwordInputRef = useRef(null);
  function handleSubmit(event) {
    console.log('Name:', nameInputRef.current.value);
    console.log('Email:', emailInputRef.current.value);
    console.log('Password:', passwordInputRef.current.value);
    event.preventDefault();
  }
  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input type="text" ref={nameInputRef} />
      </label>
      <label>
        Email:
        <input type="email" ref={emailInputRef} />
      </label>
      <label>
        Password:
        <input type="password" ref={passwordInputRef} />
      </label>
      <button type="submit">Submit</button>
    </form>
  );
}

在这个例子中,我们使用 useRef Hook 创建了一个 ref 对象,并将其赋值给每个 input 元素的 ref 属性。在 handleSubmit 函数中,我们使用 ref.current.value 来获取每个 input 元素的值。这里的每个input 元素都是非受控组件,因为它们的值由 DOM 节点直接处理,而不是由 React 组件来管理。

当然,这意味着当用户输入数据时,React 无法追踪表单元素的值。因此,当您需要访问表单元素的值时,您需要使用DOM API来获取它们。

为什么需要非受控组件

在 React 中,通常使用受控组件来处理表单。受控组件表单元素的值由 React 组件来管理,当表单数据发生变化时,React 会自动更新组件状态,并重新渲染组件。这种方式可以使得表单处理更加可靠和方便,也可以使得表单数据和应用状态之间保持一致。

但在实际的开发中,表单往往是最复杂的场景,有的表单有数十个字段,如果使用受控组件去构建表单,那么我们就需要维护大量 state,且 React 又不像 Vue 可以通过双向绑定直接修改 state 的值,每一个表单字段还需要定义一下 onChange 方法。因此在维护复杂表单时,使用受控组件会有很大的额外代码量。

为了解决受控组件带来的问题,我们可以使用非受控组件来构建表单。受控组件主要有以下三个优点

  • 可以减少组件的 代码量和复杂度,因为非受控组件不需要在组件状态中保存表单数据。
  • 可以更好地 处理大量表单数据,因为非受控组件可以让您直接操作DOM元素,而不需要将所有表单数据存储在组件状态中。
  • 可以更容易地与第三方 JavaScript 库和表单处理代码集成,因为非受控组件使您能够使用 DOM API 或 ref 直接访问表单元素,而不是在 React 中重新实现所有的表单处理逻辑。

React Hook Form 是什么?

React Hook Form 是一个基于 React 的 轻量级表单验证库。它使用了 React Hook API,让表单验证变得简单、易用、高效。React Hook Form 的主要目标是提供一个简单易用的表单验证解决方案,同时还能保持高性能和低开销。

React Hook Form 的特点都在官网首页 react-hook-form.com 中以可交互的形式展示,包括了以下几点:

  • 通过 React Hook 的方式减少使用时的代码量,简单易上手,并且移除了不必要的重复渲染:

image.png

  • 隔离重复渲染,自组件重新渲染时不会触发父组件或兄弟组件的重新渲染:

image.png

  • 订阅机制,与上一点相似,能够订阅单个输入和表单状态更新,而无需重新呈现整个表单:

image.png

  • 组件渲染速度足够快,而且代码库非常小,压缩后只有几 KB 大小,不会对页面性能造成任何影响:

image.png

React Hook Form 的使用姿势

数据收集

先看看最基础的表单实现:

import React from "react";
import { useForm } from "react-hook-form";
function MyForm() {
  const { register, handleSubmit } = useForm();
  const onSubmit = (data) => console.log(data);
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("firstName")} />
      <input {...register("lastName")} />
      <button type="submit">Submit</button>
    </form>
  );
}

咱们来分析一下这段代码:

  • 使用 useForm 函数创建一个表单对象,该函数返回一个包含 registerhandleSubmit 等方法的对象。
  • 在表单中定义两个输入框,使用 register 函数注册表单输入组件,并指定组件的名称为 firstNamelastName
  • 使用 React Hook Form 提供的 handleSubmit 函数来管理表单的提交和数据验证。

这里我们不需要定义任何 state 即可在 submit 时获取到表单中的数据,接下来我们补充一下基本的表单验证和错误提示:

import React from "react";
import { useForm } from "react-hook-form";
function MyForm() {
    const onSubmit = (data) => {
      console.log(data);
    };
    const { register, handleSubmit, formState: { errors } } = useForm();
    return (
      <form onSubmit={handleSubmit(onSubmit)}>
        <input {...register("firstName", { required: true })} />
        {errors.firstName && <p>First name is required.</p>}
        <input {...register("lastName", { required: true })} />
        {errors.lastName && <p>Last name is required.</p>}
        <button type="submit">Submit</button>
      </form>
    );
}

咱们再分析一下这段代码:

  • register 函数中可以指定表单输入组件的 验证规则 ,例如使用 required 规则来验证输入框的必填项。
  • 在表单提交处理函数中,可以调用 React Hook Form 提供的 handleSubmit 函数来自动执行表单验证,并返回验证结果。只有表单验证通过才会执行 onSubmit 方法。
  • 如果表单验证失败,可以使用 errors 对象来获取每个表单输入组件的验证错误信息,并在 UI 上显示错误提示。

register 函数是用来注册表单输入组件的,当组件注册之后,React Hook Form 会自动收集该组件的值,并根据验证规则进行验证。 register 函数会返回一个对象,其中包含了一些属性和方法,例如:

const { ref, onChange, onBlur, name } = register("firstName");

ref 属性是一个引用,指向该输入组件的 DOM 元素,onChangeonBlur 是回调函数,用于处理该组件的值变化和失去焦点事件,name 是该组件的名称。

register 函数内部会创建一个管理表单输入组件的对象,包含了该组件的名称、引用、验证规则等信息。同时,还会将该对象保存在 React Hook Form 内部的一个数据结构中。

在表单提交时,React Hook Form 会遍历管理的所有表单输入组件,并收集它们的值,并根据其注册时定义的验证规则进行验证。

到这里,一个最基本的表单验证及提交就已经实现了。当然,在实际开发中,表单之所以复杂是由于各种条件渲染及表单嵌套引起的,那么我们接下来再看看使用 React Hook Form 如何处理这些场景。

表单嵌套

还是一样,先看看示例:

父级表单

// ParentForm.jsx
import React from "react";
import { useForm, FormProvider } from "react-hook-form";
import ChildForm from "./ChildForm";
function ParentForm() {
  const methods = useForm();
  const { register, handleSubmit, formState: { errors } } = methods;
  const onSubmit = (data) => {
    console.log(data);
  };
  return (
      <FormProvider {...methods}>
        <form onSubmit={handleSubmit(onSubmit)}>
          <h2>Parent Form</h2>
          <label htmlFor="firstName">First Name</label>
          <input {...register("firstName", { required: true })} />
          {errors.firstName && <p>First name is required.</p>}
          <label htmlFor="lastName">Last Name</label>
          <input {...register("lastName", { required: true })} />
          {errors.lastName && <p>Last name is required.</p>}
          <ChildForm/>
          <button type="submit">Submit</button>
        </form>
    </FormProvider>
  );
}
export default ParentForm;

子级表单

import React from "react";
import { useFormContext } from "react-hook-form";
function ChildForm() {
  const { register, errors } = useFormContext();
  return (
    <div>
      <h2>Child Form</h2>
      <label htmlFor="childFirstName">Child First Name</label>
      <input {...register("child.firstName", { required: true })} />
      {errors.child?.firstName && <p>Child first name is required.</p>}
      <label htmlFor="childLastName">Child Last Name</label>
      <input {...register("child.lastName", { required: true })} />
      {errors.child?.lastName && <p>Child last name is required.</p>}
    </div>
  );
}
export default ChildForm;

分析一下这两个组件的代码:

  • ParentForm 组件中,我们使用 useForm hook 来获取表单的注册函数、表单状态等信息,并使用 FormProvider 组件将其传递给所有的子组件。

  • ChildForm 组件中,我们使用了 useFormContext hook 来获取父表单的注册函数和表单状态。

这里的两个表单组件间并不需要咱们去单独定义 props ,只需要将 useFormContextFormProvider 搭配使用,就可以将一个嵌套表单的逻辑分离成多个组件进行处理,且可以在父级组件提交时统一获取并处理数据。

FormProvider 是 React Hook Form 提供的一个组件,用于在 React 组件树中向下传递 useForm hook 的实例。它创建了一个 React Context,并将 useForm hook 的实例作为 Context 的值,然后通过 Context.Provider 组件将这个值传递给所有子组件.

useFormContext 则可以在子组件中获取到 FormProvider 提供的 useForm hook 的返回值。在使用 useFormContext 时,不需要手动使用 Context.Provider 将值传递给子组件,而是可以直接从 useFormContext 中获取,简化嵌套表单的代码逻辑。

条件判断

import React from "react";
import { useForm } from "react-hook-form";
function ExampleForm() {
  const { register, handleSubmit, watch } = useForm();
  const onSubmit = (data) => console.log(data);
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label htmlFor="hasAge">Do you have an age?</label>
      <select {...register("hasAge")}>
        <option value="yes">Yes</option>
        <option value="no">No</option>
      </select>
      {watch("hasAge") === "yes" && (
        <>
          <label htmlFor="age">Age</label>
          <input {...register("age", { required: true, min: 18 })} />
          {watch("age") && <p>You must be at least 18 years old.</p>}
        </>
      )}
      <button type="submit">Submit</button>
    </form>
  );
}
export default ExampleForm;

我们在 hasAge 输入框上使用了一个简单的条件渲染:只有当用户选择了 "Yes" 时,才会渲染 age 输入框。然后使用 watch 函数来监听输入框的值,并在输入的值小于 18 时显示相应的错误信息。

watch 函数用来监听指定的输入并返回它们的值。在渲染输入值和进行条件渲染时经常用到。

表单列表

import React from "react";
import { useForm, useFieldArray } from "react-hook-form";
function ListForm() {
  const { register, control, handleSubmit } = useForm({
    defaultValues: {
      list: [{ name: "" }, { name: "" }, { name: "" }]
    }
  });
  const { fields, append, remove } = useFieldArray({
    control,
    name: "list"
  });
  const onSubmit = (data) => console.log(data);
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {fields.map((field, index) => (
        <div key={field.id}>
          <input
            {...register(`list.${index}.name`, {
              required: "This field is required"
            })}
            defaultValue={field.name}
          />
          <button type="button" onClick={() => remove(index)}>
            Remove
          </button>
        </div>
      ))}
      <button type="button" onClick={() => append({ name: "" })}>
        Add Item
      </button>
      <button type="submit">Submit</button>
    </form>
  );
}
export default ListForm;

分析一下上边这段代码:

  • 在这个示例中,我们使用了 useFormuseFieldArray hook 来处理一个表单列表。其中 list 属性是一个包含 3 个空对象的数组。
  • 使用 fields.map 方法遍历 fields 数组,渲染出每一个列表项。
  • 使用 remove 方法为每个列表项添加了一个 "Remove" 按钮,使得用户可以删除不需要的列表项。我们还使用 append 方法添加了一个 "Add Item" 按钮,可以添加新的列表项。

这段代码的核心就是 useFieldArray,它专门用于处理表单列表的场景,使用时我们将 useForm 返回的 control 传入 useFieldArray hook 中,并为这个列表定义一个名字,hook 会为我们返回一些操作列表的方法,在遍历渲染列表时,我们将每一个子项单独进行注册就可以实现表单列表的动态数据更改了。

需要注意的是,当使用 useFieldArray 处理表单中的数组字段时,每个字段都必须有一个 唯一的 key 值,这样才能正确地进行数组的添加、删除、更新等操作。如果数组中的字段没有 key 值,useFieldArray 会自动为每个字段生成一个随机的 key 值。

在内部实现上,useFieldArray 使用了 useFormContext 将 FormProvider 提供的 registerunregistersetValue 函数传递给了 useFieldArray,然后在 useFieldArray 内部维护一个数组 state,保存当前的数组值和对数组的操作。

第三方组件

当需要与第三方UI组件(如<DatePicker /><Select /><Slider />等)集成时,如果使用register 注册这些第三方UI组件,可能会遇到如无法正确更新表单数据、错误处理、性能差等问题。

因此,使用Controller 是一种更好的解决方案,可以将表单数据与 React Hook Form 状态管理集成在一起,并使用render 函数来直接渲染第三方UI组件。下面放个例子:

import React from "react";
import { useForm, Controller } from "react-hook-form";
import { TextField, Button } from "@material-ui/core";
function ControllerForm() {
  const { control, handleSubmit } = useForm();
  const onSubmit = (data) =&gt; console.log(data);
  return (
    &lt;form onSubmit={handleSubmit(onSubmit)}&gt;
      &lt;Controller
        name="firstName"
        control={control}
        defaultValue=""
        rules={{ required: true }}
        render={({ field }) =&gt; (
          &lt;TextField label="First Name" {...field} /&gt;
        )}
      /&gt;
      &lt;Controller
        name="lastName"
        control={control}
        defaultValue=""
        rules={{ required: true }}
        render={({ field }) =&gt; (
          &lt;TextField label="Last Name" {...field} /&gt;
        )}
      /&gt;
      &lt;Button type="submit" variant="contained" color="primary"&gt;
        Submit
      &lt;/Button&gt;
    &lt;/form&gt;
  );
}
export default ControllerForm;

control 是一个对象,它提供了一些方法和属性,通过使用 control,我们可以将 React Hook Form 中的数据与实际渲染的表单组件进行绑定,从而让 React Hook Form 管理表单中所有的输入和校验逻辑。

field<Controller> 组件通过 render 回调函数传递给其子组件的一个对象,field 对象中包含了一些属性,如 valueonChangeonBlur 等,这些属性传递给子组件,用于设置和更新表单控件的值,以及处理表单控件的事件,如用户输入、聚焦、失焦等。

Controller的好处是可以将表单数据和表单状态统一管理,同时避免了对表单数据的手动处理。此外,它还可以优化表单的渲染性能,并提供更好的错误处理机制,因为它可以自动处理错误消息和验证规则。

Typescript 支持

React Hook Form 提供了完整的 TypeScript 支持:

import React from "react";
import { useForm, SubmitHandler } from "react-hook-form";
type FormValues = {
  firstName: string;
  lastName: string;
  age: number;
};
function MyForm() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<FormValues>();
  const onSubmit: SubmitHandler<FormValues> = (data) => console.log(data);
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("firstName", { required: true })} />
      {errors.firstName && <span>This field is required</span>}
      <input {...register("lastName", { required: true })} />
      {errors.lastName && <span>This field is required</span>}
      <input {...register("age", { required: true, min: 18 })} />
      {errors.age && (
        <span>
          {errors.age.type === "required"
            ? "This field is required"
            : "You must be at least 18 years old"}
        </span>
      )}
      <button type="submit">Submit</button>
    </form>
  );
}

我们使用 FormValues 类型定义表单数据类型,并在 useForm 钩子中使用 FormValues 泛型接口。这使得我们可以在注册表单控件时提供正确的类型定义,并在 handleSubmit 函数中提供正确的表单数据类型。还可以使用泛型来定义错误消息的类型,可以用于准确地描述表单控件的错误状态,并提供适当的错误消息。提高代码的可读性和可维护性。

总结

除了上述的一些表单使用姿势,在官方的 react-hook-form.com/advanced-us… 页面还可以看到一些高级特性的示例,例如 Schema 解析为表单实现表单组件测试表单与 API 间的数据转换 等等。

总的来说,React Hook Form 提供了一种简单、灵活的方式来管理表单状态,支持非受控组件方式以及各种复杂的表单场景,同时也提供了 Typescript 支持,是一个值得尝试的表单管理库。

以上就是React Hook Form 优雅处理表单使用指南的详细内容,更多关于React Hook Form处理表单的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

ReactHookForm优雅处理表单使用指南

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

ReactHookForm优雅处理表单使用指南

这篇文章主要为大家介绍了ReactHookForm优雅处理表单使用指南,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-03-10

React Hook Form优雅处理表单使用的方法是什么

这篇“React Hook Form优雅处理表单使用的方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“React H
2023-07-05

unplugin-svg-component优雅使用svg图标指南

这篇文章主要为大家介绍了unplugin-svg-component优雅使用svg图标指南,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-03-13

Vue中如何优雅地处理表单验证?

本文介绍了在Vue中优雅处理表单验证的方法。它涵盖了验证库、验证规则、实时和惰性验证以及错误处理。文章还提供了最佳实践,例如使用组件化方法、将验证逻辑与表单状态分离、提供可访问性支持和进行单元测试。遵循这些步骤可以增强用户体验并提高数据质量。
Vue中如何优雅地处理表单验证?
2024-04-02

PHPCMS二次开发之表单类使用指南

我们要做的就是如何把这些工具调出来使用。调用方法总共有两种。 一、视图调用法 这种方法最简单,但有局限性。在后台的模型定义字段时,选择表单的类型就会生成相应的表单类型。 二、代码调用法 这种方法比较灵活,走出了内容模块的限制,不再拘泥于内容
2022-06-12

Python音频处理库的使用指南

音频处理是多媒体领域的一个重要分支,除了音乐产业,还是人工智能、人机交互等领域的必备技能。在Python中,音频处理库是比较常用的,它可以帮助我们进行音频采集、处理和分析。本文将会介绍一些常用的Python音频处理库和它们的使用方法。一、
Python音频处理库的使用指南
2024-01-22

使用 Python 异常处理,让你的代码更加优雅

在 Python 中,异常处理是控制程序流程并防止程序崩溃的有效方法。通过使用异常处理,可以以优雅的方式处理错误,并可以让代码更加健壮可靠。
使用 Python 异常处理,让你的代码更加优雅
2024-02-25

如何使用php函数来优化表单处理和提交功能?

随着Web应用程序的发展,表单处理和提交是开发中非常重要的一部分。在PHP中,使用合适的函数来处理和提交表单可以提高代码的可读性和可维护性。本文将介绍一些常用的PHP函数,以及它们在表单处理和提交中的应用。htmlspecialchars(
2023-10-21

入门指南:使用Go语言处理大数据

Go语言作为一种开源编程语言,在近年来逐渐受到了广泛的关注和使用。它以其简洁、高效的特性,以及强大的并发处理能力而备受程序员青睐。在大数据处理领域中,Go语言也具有很强的潜力,可以用来处理海量数据、优化性能,并且可以很好地与各种大数据处理工
入门指南:使用Go语言处理大数据
2024-02-25

Win8.1使用技巧之电源模式管理优化指南

电源优化管理有何优点?电源管理的优化,能维护电脑稳定运行,降低设备各部件功耗,节省用电开销,延长设备电池及各部件的使用寿命,使设备能够长久保持稳定、低能耗、高性能的运 行状态。由于以往的Windows系统,提供台式机的电源控制较少,因此用户
2022-06-04

阿里云代理再享85折优惠券使用指南

阿里云是一家全球领先的云计算服务提供商,其服务包括计算、存储、网络、安全、数据库、大数据、人工智能等。阿里云代理再享85折优惠券是阿里云为了鼓励用户使用其云服务而推出的优惠活动。本文将详细介绍如何使用阿里云代理再享85折优惠券。一、领取优惠券首先,你需要在阿里云官网或者阿里云官方APP上找到优惠券领取入口,一般在
阿里云代理再享85折优惠券使用指南
2023-11-07

HTML布局指南:如何使用伪类选择进行表单样式控制

简介:在网页设计中,表单是不可或缺的元素之一,常常用于收集用户输入信息。为了提升用户体验和界面美观度,我们需要对表单进行样式控制。本文将介绍如何使用伪类选择器来对表单进行定制化样式。一、了解伪类选择器:伪类选择器是一种CSS选择器,通过为特
2023-10-21

如何使用 PHP 内置函数处理表单数据?

php 内置函数处理表单数据包括验证、清理和安全处理,具体步骤如下:验证数据是否为空或已设置(empty()、isset())去除字符串空格和过滤输入类型(trim()、filter_input())防范安全攻击,如 xss、sql 注入(
如何使用 PHP 内置函数处理表单数据?
2024-04-23

HTML列表标签使用指南:让你的网页更有条理

: HTML列表标签是网页中常用的元素,可以将内容以有序或无序的方式进行组织和显示,让网页更加清晰易读。本文将详细介绍HTML列表标签的用法,帮助您在网页中创建各种列表,提升网页的可读性和用户体验。
HTML列表标签使用指南:让你的网页更有条理
2024-02-11

小程序表单校验uni-forms的正确使用方式以及避坑指南

因微信小程序上没有自带表单验证,为了实现就自己做了个表单验证,下面这篇文章主要给大家介绍了关于小程序表单校验uni-forms的正确使用方式以及避坑指南,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
2022-11-13

编程热搜

目录