React Hooks Form
react-hook-form
是一个专注于管理 React
表单状态的库。它的核心理念是利用 React Hooks
来简化表单的处理过程。与其他表单管理库相比,它的优势在于性能和简洁性。它不需要在每次输入更改时重新渲染整个表单组件,从而提高了性能。
其实最主要的原因是有很多组件库并没有提供表单校验功能,而且每个组件库的表单校验功能用法都不一致,因此我选择使用 ``react-hook-form
这样在使用不同组件库时表单的校验方式完成了统一。
下面将介绍一下这个表单校验库:
安装
npm install react-hook-form
官方快速入门教程: Get Started (react-hook-form.com)
Register
用于注册表单字段使表单能够监听到该字段的数据
import { useState } from "react";
import { SubmitHandler, useForm } from "react-hook-form";
interface FormData {
name: string;
age: number;
}
export default () => {
const [defaultValues, setDefaultValues] = useState({ name: "", age: 0 })
const { register, handleSubmit } = useForm<FormData>({ defaultValues });
const onSubmit: SubmitHandler<FormData> = (data, event) => {
// 阻止默认提交行为
event?.preventDefault();
console.log(data)
// {name: 'yuyang', age: '21'}
}
return (
<>
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name")} type="text" />
<input {...register("age")} type="text" />
<button type="submit">提交</button>
</form>
</>
)
}
约束表单数据
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name", { required: true, maxLength: 3 })} type="text" />
<input {...register("age", { min: 0, max: 99 })} type="text" />
<button type="submit">提交</button>
</form>
当然也可以使用正则
<input {...register("age", { pattern: /^(0|[1-9][0-9]?)$/ })} type="text" />
显示错误信息
const { register, handleSubmit, formState: { errors } } = useForm<FormData>({ defaultValues });
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register("name",
{
required: { value: true, message: "请输入名称" },
maxLength: { value: 3, message: "名称不符合长度" }
})}
type="text"
/>
<span>{errors.name && errors.name.message}</span>
<input {...register("age", { pattern: { value: /^(0|[1-9][0-9]?)$/, message: "输入的年龄错误" } })} type="text" />
<span>{errors.age && errors.age.message}</span>
<button type="submit">提交</button>
</form>
重置表单数据
reset
它的作用是重置表单 defaultValues
初始数据,我们一般用于获取接口数据后,将数据回显给表单
const [defaultValues, setDefaultValues] = useState({ name: "", age: 0 })
const { register, handleSubmit, reset } = useForm<FormData>({ defaultValues });
示例: 1
秒钟后将数据更改
useEffect(() => {
setTimeout(() => {
// 错误:如果我们直接修改它的值,实际上确实可以修改,不过数据虽然更改了但表单数据还是之前的并不会同步
// setDefaultValues({ name: "yuyang", age: 21 })
// 所以可以使用 reset 来重置默认数据实现回显效果
reset({ name: "宇阳", age: 21 })
}, 1000)
}, [])
手动触发表单验证
通过 trigger
可以实现手动触发表单的验证,通常适用于表单失去焦点时验证表单
const { register, handleSubmit, formState: { errors }, trigger } = useForm<FormData>({ defaultValues });
<input
{...register("name", { required: { value: true, message: "请输入名称" } })}
type="text"
onBlur={() => { trigger('name') }}
/>
<span>{errors.name && errors.name?.message}</span>
监听表单数据变化
通过 watch
可以监听表单某一项或整个表单的数据变化
const { register, handleSubmit, watch } = useForm<FormData>({ defaultValues });
// 监听单个数据的变化
const data = watch("name");
// const data = watch("name", "宇阳"); // 默认值
// 宇阳
// 监听多个数据的变化
// const data = watch(["name", "age"]);
// ["宇阳", "21"]
// 监听表单所有数据的变化
// const data = watch();
// { name: '宇阳', age: '21' }
useEffect(() => {
console.log(data);
}, [data])
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name")} type="text" />
<input {...register("age")} type="text" />
<button type="submit">提交</button>
</form>
自定义行为
默认情况下 react hooks form
自动帮我们对 value
和 onChange
等操作做了处理,所以我们可以不用写他们。
但有些场合,比如说我们需要对输入的值做一些处理,那么我们可以自定义 onChange
但需要注意的是需要手动调用一下 register("age").onChange(e)
,否则这个表单就失去了 react hooks form
的特性
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name")} type="text" />
<input {...register("age")} type="text" onChange={(e) => {
// 在这里做一些自定义的操作
console.log(e.target.value);
// 但一定不要忘记 调用 onChange
register("age").onChange(e)
}} />
<button type="submit">提交</button>
</form>
其他 API
这些比较有用,但过于简单,就不必展开细说了,大家可以查阅官方文档
获取表单焦点
参考: https://react-hook-form.com/docs/useform/setfocus
获取表单的值
参考: https://react-hook-form.com/docs/useform/getvalues
操作表单的值
参考: https://react-hook-form.com/docs/useform/setvalue
清除表单验证的错误
参考: https://react-hook-form.com/docs/useform/clearerrors
Controller(推荐)
它的功能与 Register
类似,都是用于注册表单的字段 并且 Register
的 API
都可以使用。但不同的是该方式时候于第三方组件库使用,因为有些组件库可能并没有提供 value
和 onChange
或者属性名不一致导致使用 Register
会有些问题。
所以该方式适用于第三方组件库。如果组件库具有 value
和 onChange
那么使用Register
也是可行的,不过最好使用 Controller
方式。下面将演示一下它的使用:
import { Input } from "@nextui-org/react";
import { useState } from "react";
import { Controller, SubmitHandler, useForm } from "react-hook-form";
interface FormData {
name: string;
age: number;
}
export default () => {
const [defaultValues, setDefaultValues] = useState({ name: "", age: 0 })
const { register, handleSubmit, control, formState: { errors }, trigger } = useForm<FormData>({ defaultValues });
const onSubmit: SubmitHandler<FormData> = (data, event) => {
// 阻止默认提交行为
event?.preventDefault();
console.log(data)
// {name: 'yuyang', age: '21'}
}
return (
<>
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="name"
control={control}
rules={{ required: '请输入名称' }}
render={({ field }) => (
<>
<Input {...field} type="text" onChange={(e) => {
// 自定义行为
console.log(e.target.value);
// 务必调用 onChange
field.onChange(e)
}} onBlur={() => trigger('name')} />
<span>{errors.name && errors.name?.message}</span>
</>
)}
/>
{/* 两种方式也可以混合使用 */}
<input {...register("age")} type="text" />
<button type="submit">提交</button>
</form>
</>
)
}
总结:
虽然很明确组件库具有 value
、onChange
时 Register
也可以使用 或者 Controller
也可以直接使用原生表单。但还是有必要区分一下
Register: 用于简单的原生表单
Controller: 用于复杂的第三方组件表单