💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、豆包、星火、月之暗面及文生图、文生视频 广告
[TOC] > [home](https://react-hook-form.com/) ## 示例 - 可以像 vue 的 v-model 一样处理 - 可以设置是否必选之类的属性 ## 语法 ### 表单 useForm ``` const { register, unregister, formState, watch, handleSubmit, reset, resetField, setError, clearErrors, setValue, setFocus, getValues, getFieldState, trigger, control, Form } = useForm({ // 默认值 defaultValues: { username: '', password: '' }, // 提交模式 mode: 'onSubmit' }); ``` ### 可用属性 ``` required min max minLength maxLength pattern validate ``` example ``` <input {...register("firstName", { required: true, maxLength: 20 })} /> <input {...register("lastName", { pattern: /^[A-Za-z]+$/i })} /> <input type="number" {...register("age", { min: 18, max: 99 })} /> ``` ## 示例 ### hello-world ``` import { useState } from "react"; import { useForm } from "react-hook-form"; import Header from "./Header"; export function App() { const { register, handleSubmit } = useForm(); const [data, setData] = useState(""); return ( <form onSubmit={handleSubmit((data) => setData(JSON.stringify(data)))}> <Header /> <input {...register("firstName")} placeholder="First name" /> <select {...register("category", { required: true })}> <option value="">Select...</option> <option value="A">Option A</option> <option value="B">Option B</option> </select> <textarea {...register("aboutYou")} placeholder="About you" /> <p>{data}</p> <input type="submit" /> </form> ); } ``` ### 对第三方组件 ``` import Select from "react-select" import { useForm, Controller, SubmitHandler } from "react-hook-form" import { Input } from "@material-ui/core" interface IFormInput { firstName: string lastName: string iceCreamType: { label: string; value: string } } const App = () => { const { control, handleSubmit } = useForm({ defaultValues: { firstName: "", lastName: "", iceCreamType: {}, }, }) const onSubmit: SubmitHandler<IFormInput> = (data) => { console.log(data) } return ( <form onSubmit={handleSubmit(onSubmit)}> <Controller name="firstName" control={control} render={({ field }) => <Input {...field} />} /> <Controller name="iceCreamType" control={control} render={({ field }) => ( <Select {...field} options={[ { value: "chocolate", label: "Chocolate" }, { value: "strawberry", label: "Strawberry" }, { value: "vanilla", label: "Vanilla" }, ]} /> )} /> <input type="submit" /> </form> ) } ``` ### 配合 zod 的最佳实践 ``` import { useForm, SubmitHandler } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import * as z from "zod"; // 定义表单验证 Schema const formSchema = z.object({ username: z.string() .min(3, "用户名至少3个字符") .max(20, "用户名最多20个字符"), email: z.string() .email("请输入有效的邮箱地址"), password: z.string() .min(6, "密码至少6个字符") .regex(/[A-Z]/, "密码必须包含大写字母"), confirmPassword: z.string() }).refine((data) => data.password === data.confirmPassword, { message: "两次密码输入不一致", path: ["confirmPassword"], }); // 定义表单数据类型 type FormData = z.infer<typeof formSchema>; function RegistrationForm() { const { register, handleSubmit, formState: { errors, isSubmitting }, reset, watch } = useForm<FormData>({ resolver: zodResolver(formSchema), defaultValues: { username: "", email: "", password: "", confirmPassword: "" } }); const onSubmit: SubmitHandler<FormData> = async (data) => { try { // 模拟API调用 await new Promise(resolve => setTimeout(resolve, 1000)); console.log(data); reset(); // 提交成功后重置表单 alert("注册成功!"); } catch (error) { console.error("提交失败:", error); } }; return ( <form onSubmit={handleSubmit(onSubmit)} className="space-y-4"> <div> <label className="block mb-1">用户名</label> <input {...register("username")} className="w-full px-3 py-2 border rounded" placeholder="请输入用户名" /> {errors.username && ( <p className="text-red-500 text-sm mt-1"> {errors.username.message} </p> )} </div> <div> <label className="block mb-1">邮箱</label> <input {...register("email")} type="email" className="w-full px-3 py-2 border rounded" placeholder="请输入邮箱" /> {errors.email && ( <p className="text-red-500 text-sm mt-1"> {errors.email.message} </p> )} </div> <div> <label className="block mb-1">密码</label> <input {...register("password")} type="password" className="w-full px-3 py-2 border rounded" placeholder="请输入密码" /> {errors.password && ( <p className="text-red-500 text-sm mt-1"> {errors.password.message} </p> )} </div> <div> <label className="block mb-1">确认密码</label> <input {...register("confirmPassword")} type="password" className="w-full px-3 py-2 border rounded" placeholder="请再次输入密码" /> {errors.confirmPassword && ( <p className="text-red-500 text-sm mt-1"> {errors.confirmPassword.message} </p> )} </div> <button type="submit" disabled={isSubmitting} className="w-full py-2 px-4 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:bg-gray-400" > {isSubmitting ? "注册中..." : "注册"} </button> </form> ); } export default RegistrationForm; ```