在TS环境中React Hook Form表单的创建(一)

创建项目

使用yarn

yarn create vite

使用npm

npm create vite@latest

安装,选择Reac和TypeScript

 % npm create vite@latest
✔ Project name: … react-hook-form-ts
✔ Select a framework: › React
✔ Select a variant: › TypeScript

Scaffolding project in /Users/hedy/Projects/react/react-hook-form-ts...

Done. Now run:

  cd react-hook-form-ts
  yarn
  yarn dev

执行命令后,将创建react-hook-form-ts,因此将其移动并执行“yarn install”命令。

cd react-hook-form-ts
 % yarn install

不使用 React Hook Form 库

在不使用 React Hook Form 库的情况下,你可以使用 React 创建表单的方法。一般来说,有两种创建表单的方式:一种是使用 useState Hook,另一种是使用 useRef。前者被称为受控组件(Controlled Component),后者被称为非受控组件(Uncontrolled Component)。它们之间的主要区别在于如何控制 React 中的输入元素的值。下面将介绍如何在不使用 Hook 的情况下创建一个包含 emailpassword 两个输入字段的登录表单,以及如何在/src/App.tsx 文件中进行验证。

使用 useState 时
import React, { useState } from 'react'
import './App.css'

function App({
    const [email, setEmail] = useState<string>('');
    const [password, setPassword] = useState<string>('');

    const handleChangeEmail = (e:React.ChangeEvent<HTMLInputElement>) => {
        setEmail(e.target.value)
    }
    const handleChangePassword = (e:React.ChangeEvent<HTMLInputElement>) => {
        setPassword(e.target.value)
    }

    const handleSubmit = (e:React.FormEvent<HTMLFormElement>) => {
      e.preventDefault();
      console.log({
          email,
          password
      })
    }

    return (
    <>
      <h1>登录</h1>
      <form onSubmit={handleSubmit}>
          <div>
              <label htmlFor="email">邮箱</label>
              <input
                  id="email"
                  name="email"
                  value={email}
                  onChange={handleChangeEmail}
              />

          </div>
          <div>
              <label htmlFor="password">密码</label>
              <input
                  id="password"
                  type="password"
                  name="password"
                  value={password}
                  onChange={handleChangePassword}
              />

          </div>
          <div>
              <button type="submit">登录</button>
          </div>
      </form>

    </>

  )
}

export default App

useState中定义了emailpassword,初始值为空。当你在输入元素中输入字符时,将执行handleChange函数并保存在电子邮件和密码中输入的值。当点击登录按钮时,会执行handleSubmit函数,并将控制台中输入的值显示为对象。

在浏览器中:在TS环境中React Hook Form表单的创建(一)

还可以这么写,如下代码:

import React, { useState } from 'react'
import './App.css'

function App({
    const [email, setEmail] = useState<string>('');
    const [password, setPassword] = useState<string>('');
    return (
    <>
      <h1>登录</h1>
      <form onSubmit={(e:React.FormEvent<HTMLFormElement>) => {
          e.preventDefault();
          console.log({
              email,
              password
          })
      }}>
          <div>
              <label htmlFor="email">邮箱</label>
              <input
                  id="email"
                  name="email"
                  value={email}
                  onChange={(e:React.ChangeEvent<HTMLInputElement>) => {
                      setEmail(e.target.value)
                  }}
              />
          </div>
          <div>
              <label htmlFor="password">密码</label>
              <input
                  id="password"
                  type="password"
                  name="password"
                  value={password}
                  onChange={(e:React.ChangeEvent<HTMLInputElement>) => {
                      setPassword(e.target.value)
                  }}
              />
          </div>
          <div>
              <button type="submit">登录</button>
          </div>
      </form>

    </>
  )
}

export default App

还可以使用 useState 中的对象来保存表单输入值。使用事件对象的目标中包含的名称和值更新定义的 formData 值。

import React, { useState } from 'react'
import './App.css'

function App({
    const [formData,setFormData] =useState<{email:string;password:string}>({
        email:'',
        password:''
    });

    const handleChange = (e:React.ChangeEvent<HTMLInputElement>) => {
      const {name,value} = e.target
        setFormData({...formData,[name]:value})
    }

    const handleSubmit = (e:React.FormEvent<HTMLFormElement>) => {
      e.preventDefault();
      console.log(formData)
    }
    return (
    <>
      <h1>登录</h1>
      <form onSubmit={handleSubmit}>
          <div>
              <label htmlFor="email">邮箱</label>
              <input
                  id="email"
                  name="email"
                  value={formData.email}
                  onChange={handleChange}
              />

          </div>
          <div>
              <label htmlFor="password">密码</label>
              <input
                  id="password"
                  type="password"
                  name="password"
                  value={formData.password}
                  onChange={handleChange}
              />

          </div>
          <div>
              <button type="submit">登录</button>
          </div>
      </form>

    </>

  )
}

export default App
使用 useRef

以下是使用 useRef Hook 重写的登录表单,它用于直接引用输入元素的值。useRef 既可以用于引用 DOM 元素以直接操作它们,也可以用于存储类似于 useState 的值。在这里,我们将定义 emailRefpasswordRef,并将它们分别分配给 emailpassword 输入元素的 ref 属性。通过 emailRefpasswordRef,我们可以直接访问输入元素并获取其值。需要注意的是,useRef 的类型需要根据引用的元素进行定义。由于 emailRefpasswordRef 引用的是输入元素,因此类型被设置为 HTMLInputElement | null,因为引用可能为 null。在访问属性时,我们使用了 ?. 操作符来处理潜在的 null 值。

import React, {useRef} from 'react'
import './App.css'

function App({
   const emailRef = useRef<HTMLInputElement>(null);
   const passwordRef = useRef<HTMLInputElement>(null);
    const handleSubmit = (e:React.FormEvent<HTMLFormElement>) => {
      e.preventDefault();
      console.log({
          email:emailRef.current?.value,
          password:passwordRef.current?.value
      })
    }

    return (
    <>
      <h1>登录</h1>
      <form onSubmit={handleSubmit}>
          <div>
              <label htmlFor="email">邮箱</label>
              <input
                  id="email"
                  name="email"
                  ref={emailRef}
              />

          </div>
          <div>
              <label htmlFor="password">密码</label>
              <input
                  id="password"
                  type="password"
                  name="password"
                 ref={passwordRef}
              />

          </div>
          <div>
              <button type="submit">登录</button>
          </div>
      </form>

    </>

  )
}

export default App

useState Hook 和 useRef Hook 创建的登录界面在界面和显示的内容方面没有区别,都允许在输入后单击登录按钮以将输入的值显示为对象。

尽管界面和输出内容相同,但由于使用了两种不同的 Hook 功能(useState Hook 和 useRef Hook),因此在内部处理方面存在重要差异。在使用 useState Hook 时,每次输入文本时都会触发”重新渲染”,而在使用 useRef Hook 时,由于元素(input)本身持有值,因此不会触发”重新渲染”。你可以通过在 handleSubmit 函数下添加 console.log('重新渲染') 来直观地查看这些差异。这两种方法都在管理表单输入方面有其用途,具体取决于你的需求和偏好。useState Hook 用于受控组件,使你可以更容易地处理输入值的状态,并在每次更改时进行重新渲染。而 useRef Hook 则用于非受控组件,允许你直接引用输入元素的值,减少了重新渲染的频率。

使用react-hook-form库

安装
npm install react-hook-form

React Hook Form 是一个基于 Hook 的表单管理库,使用 useForm Hook 来创建表单。从 useForm 返回的对象包含多个属性,但我们将使用其中最基本的 registerhandleSubmit 来创建输入表单。

用法

利用useForm我们可以重写一下代码:

import './App.css'
import {useForm} from "react-hook-form";
type FormData = {
    email:string;
    password:string
}

function App({
    const { register, handleSubmit } = useForm<FormData>();
    const onSubmit = handleSubmit((data) => console.log(data))
    return (
    <>
      <h1>登录</h1>
      <form onSubmit={onSubmit}>
          <div>
              <label htmlFor="email">邮箱</label>
              <input
                  id="email"
                  {...register('email')}
              />

          </div>
          <div>
              <label htmlFor="password">密码</label>
              <input
                  id="password"
                  type="password"
                  {...register('password')}
              />

          </div>
          <div>
              <button type="submit">登录</button>
          </div>
      </form>
    </>

  )
}

export default App

React Hook Form 中的 register 函数用于将输入字段与表单进行关联,并返回一些与该字段相关的属性。你可以在 React Hook Form 的文档中找到有关 register 函数的详细信息,它的引数接受字段名,然后返回一个包含以下属性的对象:

  • name: 表示字段的名称,通常对应 HTML 元素的 name 属性。
  • ref: 一个引用,用于访问输入元素本身。
  • onBlur: 一个处理失去焦点事件的函数,通常用于验证和处理字段的失去焦点事件。
  • onChange: 一个处理输入变化事件的函数,通常用于更新字段的值。

通过使用 register 函数,你可以轻松地将输入字段与 React Hook Form 进行关联,而不必手动处理各种事件和状态。

你可以通过查看React Hook Form文档来了解register函数是如何配置的。在TS环境中React Hook Form表单的创建(一)

通过在 register 函数中指定参数 email,并使用返回的 namerefonBluronChange,可以将其转换为以下的熟悉形式。这几乎与使用useRef的形式相同。

看以下代码:

import './App.css'
import {useForm} from "react-hook-form";
type FormData = {
    email:string;
    password:string
}

function App({
    const { register, handleSubmit } = useForm<FormData>();
    const { name, ref, onChange, onBlur } = register('email')
    const onSubmit = handleSubmit((data) => console.log(data))
    return (
    <>
      <h1>登录</h1>
      <form onSubmit={onSubmit}>
          <div>
              <label htmlFor="email">邮箱</label>
              <input
                  id="email"
                  name={name}
                  onChange={onChange}
                  onBlur={onBlur}
                  ref={ref}
              />

          </div>
          <div>
              <label htmlFor="password">密码</label>
              <input
                  id="password"
                  type="password"
                  {...register('password')}
              />

          </div>
          <div>
              <button type="submit">登录</button>
          </div>
      </form>
    </>

  )
}

export default App

当进行输入时,将触发 onChange 事件,当将光标从输入元素移出时,将触发 onBlur 事件。ref 用于在React Hook Form中访问输入元素的引用。name 将设置为输入元素的name属性。

不过在日常的编码过程中,我们这样写比较简洁:

<input id="email" {...register('email')} />
提交onSubmit

onSubmit函数中,通过使用handleSubmit包装内部函数,可以将数据的类型推断为FormData。但是,如果在form标签的onSubmit参数中使用handleSubmit,将不会推断数据的类型。

function App({
    const { register, handleSubmit } = useForm<FormData>();
    const { name, ref, onChange, onBlur } = register('email')
    //const onSubmit = handleSubmit((data) => console.log(data))
    const onSubmit = (data) => console.log(data);
    
    return (
    <>
      <h1>登录</h1>
      <form onSubmit={handleSubmit(onSubmit)}>
在TS环境中React Hook Form表单的创建(一)
image.png

下面用SubmitHandler来设置数据类型为FormData

function App({
    const { register, handleSubmit } = useForm<FormData>();
    const { name, ref, onChange, onBlur } = register('email')
    //const onSubmit = handleSubmit((data) => console.log(data))
    const onSubmit:SubmitHandler<FormData> = (data) => console.log(data);
设置验证规则

验证是检查输入值的功能。例如,在通常情况下,创建用户时需要设置密码。如果想要限制密码的字符数,可以使用验证功能。通过使用验证,可以在用户未达到字符数限制时,在将输入内容发送到服务器之前向用户传达错误消息。

React Hook Form的验证可以通过register函数进行设置。

register函数的第一个参数中,您设置了input元素的name属性的值,但在第二个参数中,您可以设置选项,以进行多个验证设置。可以使用HTML5中提供的表单控制功能来进行验证。支持的验证规则如下:

  • required(必需)
  • min(最小值)
  • max(最大值)
  • minLength(最小长度)
  • maxLength(最大长度)
  • pattern(模式)
  • validate(自定义验证)

比如设置required

<input
  id="email"
  {...register('email',{required:true})}
/>

现在我们邮箱为空的情况,点击登录按钮,则浏览器控制台不会显示任何内容,意味着onSubmit 函数将不会被执行。

显示错误

我们只设置了必填,没有写显示验证错误的提示消息,下面我们来添加错误处理代码:

import './App.css'
import {SubmitHandler, useForm} from "react-hook-form";
type FormData = {
    email:string;
    password:string
}

function App({
    const { register, handleSubmit, formState: { errors } } = useForm<FormData>();
    const onSubmit:SubmitHandler<FormData> = (data) => console.log(data);

    return (
    <>
      <h1>登录</h1>
      <form onSubmit={handleSubmit(onSubmit)}>
          <div>
              <label htmlFor="email">邮箱</label>
              <input
                  id="email"
                  {...register('email',{required:true})}
              />

              {errors.email && <div style={{color:'red'}}>请先填写邮箱</div>}
          </div>
          <div>
              <label htmlFor="password">密码</label>
              <input
                  id="password"
                  type="password"
                  {...register('password')}
              />

          </div>
          <div>
              <button type="submit">登录</button>
          </div>
      </form>
    </>

  )
}

export default App

设置后,如果在电子邮件输入字段为空时单击登录按钮,则会显示错误消息。在TS环境中React Hook Form表单的创建(一)

如果要为必填属性设置一个值,可以通过将注册函数选项中设置的所需值从 true 更改为字符串来将字符串设置为消息属性。

 <div>
      <label htmlFor="email">邮箱</label>
      <input
          id="email"
          {...register('email',{required:'邮箱不能为空!'})}
      />

      {errors.email?.message && <div style={{color:'red'}}>{errors.email.message}</div>}
      {/*{errors.email && <div style={{color:'red'}}>请先填写邮箱</div>}*/}
    </div>

效果还是跟前面的一样。

对于错误消息,还可以使用对象而不是字符串来设置 required 的值。其他验证规则使用对象规范方法。

<input
  id="email"
  {...register('email', {
    required: {
      valuetrue,
      message'邮箱不能为空!',
    },
  })}
/>
设置多重验证

除了设置必填选项外,如果输入内容有字符限制,可以使用minLengthmaxLength验证规则。

使用密码设置 minLength。验证有两个设置:requiredminLength。由于 minLength 的值设置为 8,因此如果不输入 8 个或更多字符,minLength 验证将失败。

 <div>
      <label htmlFor="password">密码</label>
      <input
          id="password"
          type="password"
          {...register('password',{
              required: {
                  value: true,
                  message: '密码不能为空!'
              },
              minLength: {
                  value: 8,
                  message:'密码长度不能少于8位数'
              }
          })}
      />

      {errors.password?.type === 'required' && (
          <div style={{color:'red'}}>{errors.password.message}</div>
      )}
      {errors.password?.type === 'minLength' && (
          <div style={{color:'red'}}>{errors.password.message}</div>
      )}
 </div>

虽然我们这样子写也可以显示错误信息,但默认设置下,每个输入字段只能保留一个错误信息。要获取多个验证错误,需要在useForm的参数中设置criteriaMode的选项。默认情况下,criteriaMode的值为”firstError“,因此将其更改为”all“。

 const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
        criteriaMode'all'
  });

为了验证criteriaMode的行为,我们将添加验证规则的”pattern“来触发多个验证错误。在”pattern“规则中,您可以使用正则表达式。在以下示例中,只有输入字母才能通过验证,如果输入数字或符号,则验证将失败。

<div>
      <label htmlFor="password">密码</label>
      <input
          id="password"
          type="password"
          {...register('password',{
              required: {
                  value: true,
                  message: '密码不能为空!'
              },
              pattern: {
                  value: /^[A-Za-z]+$/,
                  message: '请仅输入字母字符',
              },
              minLength: {
                  value: 8,
                  message:'密码长度不能少于8位数'
              }
          })}
      />

      {errors.password?.type === 'required' && (
          <div style={{color:'red'}}>{errors.password.message}</div>
      )}
      {errors.password?.types?.pattern && (
          <div style={{color:'red'}}>{errors.password.types.pattern}</div>
      )}
      {errors.password?.type === 'minLength' && (
          <div style={{color:'red'}}>{errors.password.message}</div>
      )}
  </div>

当输入密码中包含数字时,errors.password将包含以下内容。在以前的版本中,它只包含messagereftype这三个属性,但现在新增了types属性,用于存储两个验证错误的信息。这样子就可以一次性显示多个错误信息了。在TS环境中React Hook Form表单的创建(一)

设置初始值

可以通过在useForm Hook的参数对象中使用defalutValues来设置输入元素的初始值。

const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
        criteriaMode'all',
        defaultValues: {
            email'243425345@qq.com',
            password'1233444'
        }
});

在浏览器中查看时,将显示设置的初始值。

在TS环境中React Hook Form表单的创建(一)
image.png

下一篇文章我们继续来了解react-hook-form,如果该文章对你有用,那就关注一下吧!

原文始发于微信公众号(大前端编程教学):在TS环境中React Hook Form表单的创建(一)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/224488.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!