跳至內容

開始使用

使用 React Hook Form 輕鬆驗證表單。

安裝

安裝 React Hook Form 只需一個指令即可開始使用。

npm install react-hook-form

範例

以下程式碼片段展示了一個基本用法範例

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>
)
}
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>
)
}

React 網頁應用程式影片教學

此影片教學說明了 React Hook Form 的基本用法和概念。

註冊欄位

React Hook Form 的一個關鍵概念是將您的組件註冊到 hook 中。這將使其值可用於表單驗證和提交。

注意:每個欄位都必須有一個 name 作為註冊過程的鍵值。

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>
)
}
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>
)
}

套用驗證

React Hook Form 透過與現有的 HTML 表單驗證標準保持一致,讓表單驗證變得容易。

支援的驗證規則列表

  • required(必填)
  • min(最小值)
  • max(最大值)
  • minLength(最小長度)
  • maxLength(最大長度)
  • pattern(模式)
  • validate(驗證)

您可以在register 章節中閱讀有關每個規則的更多詳細資訊。

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>
)
}
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>
)
}

整合現有表單

整合現有表單應該很簡單。重要的步驟是註冊組件的 ref 並將相關的 props 分派給您的輸入框。

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>
)
}
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>
)
}

與 UI 函式庫整合

React Hook Form 讓與外部 UI 組件庫整合變得容易。如果組件沒有公開輸入框的 ref,那麼您應該使用 Controller 組件,它將負責註冊過程。

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>
)
}
import Select from "react-select"
import { useForm, Controller } from "react-hook-form"
import { Input } from "@material-ui/core"
const App = () => {
const { control, handleSubmit } = useForm({
defaultValues: {
firstName: "",
select: {},
},
})
const onSubmit = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="firstName"
control={control}
render={({ field }) => <Input {...field} />}
/>
<Controller
name="select"
control={control}
render={({ field }) => (
<Select
{...field}
options={[
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" },
]}
/>
)}
/>
<input type="submit" />
</form>
)
}

整合受控輸入

這個函式庫擁抱非受控組件和原生 HTML 輸入框。 然而,很難避免使用外部受控組件,例如 React-SelectAntDMUI。 為了簡化這一點,我們提供了一個包裝器組件 Controller 來簡化整合過程,同時仍然讓您可以自由使用自定義註冊。

使用組件 API

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>({
defaultValues: {
MyCheckbox: false,
},
})
const onSubmit: SubmitHandler<IFormInputs> = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="MyCheckbox"
control={control}
rules={{ required: true }}
render={({ field }) => <Checkbox {...field} />}
/>
<input type="submit" />
</form>
)
}
import { TextField } from "@material-ui/core"
import { useController, useForm } from "react-hook-form"
function Input({ control, name }) {
const {
field,
fieldState: { invalid, isTouched, isDirty },
formState: { touchedFields, dirtyFields },
} = useController({
name,
control,
rules: { required: true },
})
return (
<TextField
onChange={field.onChange} // send value to hook form
onBlur={field.onBlur} // notify when input is touched/blur
value={field.value} // input value
name={field.name} // send down the input name
inputRef={field.ref} // send input ref, so we can focus on input when error appear
/>
)
}

使用 Hooks API

import * as React from "react"
import { useForm, useController, UseControllerProps } from "react-hook-form"
type FormValues = {
FirstName: string
}
function Input(props: UseControllerProps<FormValues>) {
const { field, fieldState } = useController(props)
return (
<div>
<input {...field} placeholder={props.name} />
<p>{fieldState.isTouched && "Touched"}</p>
<p>{fieldState.isDirty && "Dirty"}</p>
<p>{fieldState.invalid ? "invalid" : "valid"}</p>
</div>
)
}
export default function App() {
const { handleSubmit, control } = useForm<FormValues>({
defaultValues: {
FirstName: "",
},
mode: "onChange",
})
const onSubmit = (data: FormValues) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Input control={control} name="FirstName" rules={{ required: true }} />
<input type="submit" />
</form>
)
}
import { TextField } from "@material-ui/core"
import { useController, useForm } from "react-hook-form"
function Input({ control, name }) {
const {
field,
fieldState: { invalid, isTouched, isDirty },
formState: { touchedFields, dirtyFields },
} = useController({
name,
control,
rules: { required: true },
})
return (
<TextField
onChange={field.onChange} // send value to hook form
onBlur={field.onBlur} // notify when input is touched/blur
value={field.value} // input value
name={field.name} // send down the input name
inputRef={field.ref} // send input ref, so we can focus on input when error appear
/>
)
}

與全域狀態整合

這個函式庫不需要您依賴狀態管理函式庫,但您可以輕鬆地與它們整合。

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({
defaultValues: {
firstName: "",
lastName: "",
},
})
// Submit your data into Redux store
const onSubmit = (data) => props.updateAction(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("firstName")} />
<input {...register("lastName")} />
<input type="submit" />
</form>
)
}
// Connect your component with redux
connect(
({ firstName, lastName }) => ({ firstName, lastName }),
updateAction
)(YourForm)

處理錯誤

React Hook Form 提供了一個 errors 物件來顯示表單中的錯誤。 errors 的類型將返回給定的驗證約束。以下範例展示了一個必填驗證規則。

import { useForm } from "react-hook-form"
export default function App() {
const {
register,
formState: { errors },
handleSubmit,
} = useForm()
const onSubmit = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register("firstName", { required: true })}
aria-invalid={errors.firstName ? "true" : "false"}
/>
{errors.firstName?.type === "required" && (
<p role="alert">First name is required</p>
)}
<input
{...register("mail", { required: "Email Address is required" })}
aria-invalid={errors.mail ? "true" : "false"}
/>
{errors.mail && <p role="alert">{errors.mail.message}</p>}
<input type="submit" />
</form>
)
}

與服務整合

要將 React Hook Form 與服務整合,您可以使用函式庫內建的提交處理功能。<Form /> 組件允許您輕鬆地將表單數據發送到 API 端點或其他服務。深入了解 Form 組件

import { Form } from "react-hook-form"
function App() {
const { register, control } = useForm()
return (
<Form
action="/api/save" // Send post request with the FormData
// encType={'application/json'} you can also switch to json object
onSuccess={() => {
alert("Your application is updated.")
}}
onError={() => {
alert("Submission has failed.")
}}
control={control}
>
<input {...register("firstName", { required: true })} />
<input {...register("lastName", { required: true })} />
<button>Submit</button>
</Form>
)
}

結構描述驗證

我們也支援基於結構描述的表單驗證,使用 YupZodSuperstructJoi,您可以將您的 schema 作為可選配置傳遞給 useForm。它將根據結構描述驗證您的輸入數據,並返回 errors 或有效的結果。

步驟 1:Yup 安裝到您的項目中。

npm install @hookform/resolvers yup

步驟 2:準備您的驗證結構描述並使用 React Hook Form 註冊輸入框。

import { useForm } from "react-hook-form"
import { yupResolver } from "@hookform/resolvers/yup"
import * as yup from "yup"
const schema = yup
.object({
firstName: yup.string().required(),
age: yup.number().positive().integer().required(),
})
.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>
)
}

React Native

您將在 React Native 中獲得相同的效能提升和增強。要與輸入組件整合,您可以使用 Controller 包裝它。

Expo JS
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({
defaultValues: {
firstName: "",
lastName: "",
},
})
const onSubmit = (data) => console.log(data)
return (
<View>
<Controller
control={control}
rules={{
required: true,
}}
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
placeholder="First name"
onBlur={onBlur}
onChangeText={onChange}
value={value}
/>
)}
name="firstName"
/>
{errors.firstName && <Text>This is required.</Text>}
<Controller
control={control}
rules={{
maxLength: 100,
}}
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
placeholder="Last name"
onBlur={onBlur}
onChangeText={onChange}
value={value}
/>
)}
name="lastName"
/>
<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 的設計和理念著重於使用者和開發者體驗。該函式庫旨在透過微調效能和改善無障礙功能,為使用者提供更順暢的互動體驗。一些效能增強功能包括

  • 透過代理引入表單狀態訂閱模型
  • 避免不必要的計算
  • 在需要時隔離組件重新渲染

總體而言,它改善了使用者與應用程式互動時的使用者體驗。 至於開發者,我們引入了內建驗證,並與 HTML 標準緊密結合,允許使用強大的驗證方法和與結構描述驗證原生整合來進一步擴展。 此外,在 TypeScript 的幫助下,擁有一個強類型檢查的表單可以提供早期的建構時反饋,以幫助和引導開發者建構強大的表單解決方案。

以下由 Bill 發表的演講展示了一些想法和設計模式

感謝您的支持

如果您覺得 React Hook Form 在您的項目中有用,請考慮給它點星並支持它。