创建项目
使用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 的情况下创建一个包含 email
和 password
两个输入字段的登录表单,以及如何在/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
中定义了email
和password
,初始值为空。当你在输入元素中输入字符时,将执行handleChange
函数并保存在电子邮件和密码中输入的值。当点击登录按钮时,会执行handleSubmit
函数,并将控制台中输入的值显示为对象。
还可以这么写,如下代码:
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
的值。在这里,我们将定义 emailRef
和 passwordRef
,并将它们分别分配给 email
和 password
输入元素的 ref
属性。通过 emailRef
和 passwordRef
,我们可以直接访问输入元素并获取其值。需要注意的是,useRef
的类型需要根据引用的元素进行定义。由于 emailRef
和 passwordRef
引用的是输入元素,因此类型被设置为 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
返回的对象包含多个属性,但我们将使用其中最基本的 register
和 handleSubmit
来创建输入表单。
用法
利用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函数是如何配置的。
通过在 register
函数中指定参数 email
,并使用返回的 name
、ref
、onBlur
和onChange
,可以将其转换为以下的熟悉形式。这几乎与使用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)}>

下面用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
设置后,如果在电子邮件输入字段为空时单击登录按钮,则会显示错误消息。
如果要为必填属性设置一个值,可以通过将注册函数选项中设置的所需值从 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: {
value: true,
message: '邮箱不能为空!',
},
})}
/>
设置多重验证
除了设置必填选项外,如果输入内容有字符限制,可以使用minLength
和maxLength
验证规则。
使用密码设置 minLength
。验证有两个设置:required
和 minLength
。由于 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
将包含以下内容。在以前的版本中,它只包含message
、ref
和type
这三个属性,但现在新增了types
属性,用于存储两个验证错误的信息。这样子就可以一次性显示多个错误信息了。
设置初始值
可以通过在useForm Hook的参数对象中使用defalutValues
来设置输入元素的初始值。
const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
criteriaMode: 'all',
defaultValues: {
email: '243425345@qq.com',
password: '1233444'
}
});
在浏览器中查看时,将显示设置的初始值。

下一篇文章我们继续来了解react-hook-form,如果该文章对你有用,那就关注一下吧!
原文始发于微信公众号(大前端编程教学):在TS环境中React Hook Form表单的创建(一)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/224488.html