安装
仅需一个命令,即可尝试React Hook Form。
npm install react-hook-form例子
以下代码将演示基本用法:
import React from "react"; import { useForm } from "react-hook-form"; export default function App() { const { register, handleSubmit, watch, formState: { errors } } = useForm(); const onSubmit = data => console.log(data); console.log(watch("example")); // watch input value by passing the name of it return ( /* "handleSubmit" will validate your inputs before invoking "onSubmit" */ <form onSubmit={handleSubmit(onSubmit)}> {/* register your input into the hook by invoking the "register" function */} <input defaultValue="test" {...register("example")} /> {/* include validation with required or other standard HTML validation rules */} <input {...register("exampleRequired", { required: true })} /> {/* errors will return when field validation fails */} {errors.exampleRequired && <span>This field is required</span>} <input type="submit" /> </form> ); }
import React from "react"; import { useForm, SubmitHandler } from "react-hook-form"; type Inputs = { example: string, exampleRequired: string, }; export default function App() { const { register, handleSubmit, watch, formState: { errors } } = useForm<Inputs>(); const onSubmit: SubmitHandler<Inputs> = data => console.log(data); console.log(watch("example")) // watch input value by passing the name of it return ( /* "handleSubmit" will validate your inputs before invoking "onSubmit" */ <form onSubmit={handleSubmit(onSubmit)}> {/* register your input into the hook by invoking the "register" function */} <input defaultValue="test" {...register("example")} /> {/* include validation with required or other standard HTML validation rules */} <input {...register("exampleRequired", { required: true })} /> {/* errors will return when field validation fails */} {errors.exampleRequired && <span>This field is required</span>} <input type="submit" /> </form> ); }
♦
视频教程
在本视频教程中,我演示了使用React Hook Form的基本用法和概念。
注册表单项
React Hook Form的一个关键概念是将非受控组件注册到Hook中,从而在表单校验和提交时可以获取到它的值。
注意:每个表单项都需要唯一的name
作为注册的键
注意:React Native 将需要使用手动注册 (例子如下: register('test', { required: true })
或使用Controller来包装并注册你的组件。
import React from "react"; import { useForm } from "react-hook-form"; export default function App() { const { register, handleSubmit } = useForm(); const onSubmit = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register("firstName")} /> <select {...register("gender")}> <option value="female">female</option> <option value="male">male</option> <option value="other">other</option> </select> <input type="submit" /> </form> ); }
import React from "react"; import ReactDOM from "react-dom"; import { useForm, SubmitHandler } from "react-hook-form"; enum GenderEnum { female = "female", male = "male", other = "other" } interface IFormInput { firstName: String; gender: GenderEnum; } export default function App() { const { register, handleSubmit } = useForm<IFormInput>(); const onSubmit: SubmitHandler<IFormInput> = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <label>First Name</label> <input {...register("firstName")} /> <label>Gender Selection</label> <select {...register("gender")} > <option value="female">female</option> <option value="male">male</option> <option value="other">other</option> </select> <input type="submit" /> </form> ); }
校验
React Hook Form 结合了HTML标准表单校验,使表单校验变得简单。
支持的校验规则列表:
required
min
max
minLength
maxLength
pattern
validate
你可以在注册表单项(register)阅读每个规则的更多细节。
import React from "react"; import { useForm } from "react-hook-form"; export default function App() { const { register, handleSubmit } = useForm(); const onSubmit = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register("firstName", { required: true, maxLength: 20 })} /> <input {...register("lastName", { pattern: /^[A-Za-z]+$/i })} /> <input type="number" {...register("age", { min: 18, max: 99 })} /> <input type="submit" /> </form> ); }
import React from "react"; import { useForm, SubmitHandler } from "react-hook-form"; interface IFormInput { firstName: string; lastName: string; age: number; } export default function App() { const { register, handleSubmit } = useForm<IFormInput>(); const onSubmit: SubmitHandler<IFormInput> = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register("firstName", { required: true, maxLength: 20 })} /> <input {...register("lastName", { pattern: /^[A-Za-z]+$/i })} /> <input type="number" {...register("age", { min: 18, max: 99 })} /> <input type="submit" /> </form> ); }
适配已有表单
处理已有表单很简单。关键步骤是将register
应用到已有组件的ref
中。import React from "react"; import { useForm } from "react-hook-form"; // The following component is an example of your existing Input Component const Input = ({ label, register, required }) => ( <> <label>{label}</label> <input {...register(label, { required })} /> </> ); // you can use React.forwardRef to pass the ref too const Select = React.forwardRef(({ onChange, onBlur, name, label }, ref) => ( <> <label>{label}</label> <select name={name} ref={ref} onChange={onChange} onBlur={onBlur}> <option value="20">20</option> <option value="30">30</option> </select> </> )); const App = () => { const { register, handleSubmit } = useForm(); const onSubmit = (data) => { alert(JSON.stringify(data)); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <Input label="First Name" register={register} required /> <Select label="Age" {...register("Age")} /> <input type="submit" /> </form> ); };
import React from "react"; import { Path, useForm, UseFormRegister, SubmitHandler } from "react-hook-form"; interface IFormValues { "First Name": string; Age: number; } type InputProps = { label: Path<IFormValues>; register: UseFormRegister<IFormValues>; required: boolean; }; // The following component is an example of your existing Input Component const Input = ({ label, register, required }: InputProps) => ( <> <label>{label}</label> <input {...register(label, { required })} /> </> ); // you can use React.forwardRef to pass the ref too const Select = React.forwardRef< HTMLSelectElement, { label: string } & ReturnType<UseFormRegister<IFormValues>> >(({ onChange, onBlur, name, label }, ref) => ( <> <label>{label}</label> <select name={name} ref={ref} onChange={onChange} onBlur={onBlur}> <option value="20">20</option> <option value="30">30</option> </select> </> )); const App = () => { const { register, handleSubmit } = useForm<IFormValues>(); const onSubmit: SubmitHandler<IFormValues> = data => { alert(JSON.stringify(data)); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <Input label="First Name" register={register} required /> <Select label="Age" {...register("Age")} /> <input type="submit" /> </form> ); };
使用UI库
import React from "react"; import Select from "react-select"; import { useForm, Controller } from "react-hook-form"; import Input from "@material-ui/core/Input"; const App = () => { const { control, handleSubmit } = useForm(); const onSubmit = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <Controller name="firstName" control={control} defaultValue="" 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> ); };
import React from "react"; import Select from "react-select"; import { useForm, Controller, SubmitHandler } from "react-hook-form"; import Input from "@material-ui/core/Input"; interface IFormInput { firstName: string; lastName: string; iceCreamType: {label: string; value: string }; } const App = () => { const { control, handleSubmit } = useForm<IFormInput>(); const onSubmit: SubmitHandler<IFormInput> = data => { console.log(data) }; return ( <form onSubmit={handleSubmit(onSubmit)}> <Controller name="firstName" control={control} defaultValue="" 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> ); };
受控输入
import React from "react"; import { useForm, Controller } from "react-hook-form"; import { TextField, Checkbox } from "@material-ui/core"; function App() { const { handleSubmit, control, reset } = useForm(); const onSubmit = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <Controller name="MyCheckbox" control={control} defaultValue={false} rules={{ required: true }} render={({ field }) => <Checkbox {...field} />} /> <input type="submit" /> </form> ); }
import React from "react"; import { useForm, Controller, SubmitHandler } from "react-hook-form"; import { TextField, Checkbox } from "@material-ui/core"; interface IFormInputs { TextField: string MyCheckbox: boolean } function App() { const { handleSubmit, control, reset } = useForm<IFormInputs>(); const onSubmit: SubmitHandler<IFormInputs> = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <Controller name="MyCheckbox" control={control} defaultValue={false} rules={{ required: true }} render={({ field }) => <Checkbox {...field} />} /> <input type="submit" /> </form> ); }
集成全局状态
React Hook Form不需要类似 Redux 的状态管理工具来存储状态,但你可以很容易地与任何一个集成。import React from "react"; import { useForm } from "react-hook-form"; import { connect } from "react-redux"; import updateAction from "./actions"; export default function App(props) { const { register, handleSubmit, setValue } = useForm(); // Submit your data into Redux store const onSubmit = data => props.updateAction(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <Input {...register("firstName")} defaultValue={props.firstName} /> <Input {...register("lastName")} defaultValue={props.lastName} /> <input type="submit" /> </form> ); } // Connect your component with redux connect(({ firstName, lastName }) => ({ firstName, lastName }), updateAction)(YourForm);
处理错误
React Hook Form提供了一个errors
对象显示表单中的错误。import React from "react"; import { useForm } from "react-hook-form"; export default function App() { const { register, formState: { errors }, handleSubmit } = useForm(); return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register("firstName", { required: true })} /> {errors.firstName?.type === 'required' && "First name is required"} <input {...register("lastName", { required: true })} /> {errors.lastName && "Last name is required"} <input type="submit" /> </form> ); }
import React from "react"; import { useForm, SubmitHandler } from "react-hook-form"; interface IFormInputs { firstName: string lastName: string } const onSubmit: SubmitHandler<IFormInputs> = data => console.log(data); export default function App() { const { register, formState: { errors }, handleSubmit } = useForm<IFormInputs>(); return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register("firstName", { required: true })} /> {errors.firstName && "First name is required"} <input {...register("lastName", { required: true })} /> {errors.lastName && "Last name is required"} <input type="submit" /> </form> ); }
数据格式校验
步骤1: 将Yup
安装到你的项目中。
步骤2: 准备你的数据格式以进行校验并注册到React Hook Form.
import React from "react"; import { useForm } from "react-hook-form"; import { yupResolver } from '@hookform/resolvers/yup'; import * as yup from "yup"; const schema = yup.object().shape({ firstName: yup.string().required(), age: yup.number().positive().integer().required(), }); export default function App() { const { register, handleSubmit, formState:{ errors } } = useForm({ resolver: yupResolver(schema) }); const onSubmit = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register("firstName")} /> <p>{errors.firstName?.message}</p> <input {...register("age")} /> <p>{errors.age?.message}</p> <input type="submit" /> </form> ); }
import React from "react"; import { useForm } from "react-hook-form"; import { yupResolver } from '@hookform/resolvers/yup'; import * as yup from "yup"; interface IFormInputs { firstName: string age: number } const schema = yup.object().shape({ firstName: yup.string().required(), age: yup.number().positive().integer().required(), }); export default function App() { const { register, handleSubmit, formState: { errors } } = useForm<IFormInputs>({ resolver: yupResolver(schema) }); const onSubmit = (data: IFormInputs) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register("firstName")} /> <p>{errors.firstName?.message}</p> <input {...register("age")} /> <p>{errors.age?.message}</p> <input type="submit" /> </form> ); }
React Native
你将从受控组件中获得相同的性能增强。 但是,有一些与React Native不兼容的Api(出于web和native的API差异)。 你将不得不使用Controller
或 custom register,如下面的示例所示。
import React from "react"; import { Text, View, TextInput, Button, Alert } from "react-native"; import { useForm, Controller } from "react-hook-form"; export default function App() { const { control, handleSubmit, formState: { errors } } = useForm(); const onSubmit = data => console.log(data); return ( <View> <Controller control={control} rules={{ required: true, }} render={({ field: { onChange, onBlur, value } }) => ( <TextInput style={styles.input} onBlur={onBlur} onChangeText={onChange} value={value} /> )} name="firstName" defaultValue="" /> {errors.firstName && <Text>This is required.</Text>} <Controller control={control} rules={{ maxLength: 100, }} render={({ field: { onChange, onBlur, value } }) => ( <TextInput style={styles.input} onBlur={onBlur} onChangeText={onChange} value={value} /> )} name="lastName" defaultValue="" /> <Button title="Submit" onPress={handleSubmit(onSubmit)} /> </View> ); }
TypeScript
React Hook Form是使用TypeScript
构建的,因此你可以定义一个FormData
类型 来表达表单值。
import * as React from "react"; import { useForm } from "react-hook-form"; type FormData = { firstName: string; lastName: string; }; export default function App() { const { register, setValue, handleSubmit, formState: { errors } } = useForm<FormData>(); const onSubmit = handleSubmit(data => console.log(data)); // firstName and lastName will have correct type return ( <form onSubmit={onSubmit}> <label>First Name</label> <input {...register("firstName")} /> <label>Last Name</label> <input {...register("lastName")} /> <button type="button" onClick={() => { setValue("lastName", "luo"); // ✅ setValue("firstName", true); // ❌: true is not string errors.bill; // ❌: property bill does not exist }} > SetValue </button> </form> ); }
想学更多吗?
查看React Hook Form文档,了解所有关于API的信息。