在沒有使用的表單管理套件的情況下,需要定義許多狀態來處理表單邏輯和各種錯誤狀況。而使用像 React Hook Form 這類的套件,可以減少程式碼量,並提供更多功能,使表單處理更加簡單快速。
而使用 Zod 是因為我們希望用戶在表單填入的資料是符合預期的,用 Zod 可以更簡單的定義。
在開始之前,需要先安裝以下套件:
範例程式碼
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
const userSchema = z.object({
name: z.string(),
email: z.string().email({ message: "Email is required" }),
age: z
.number({
required_error: "Age is required",
invalid_type_error: "Age must be a number",
})
.int({ message: "Age must be an integer" })
.refine((age) => age >= 18 && age <= 60, {
message: "Age must be between 18 and 60",
}),
description: z
.string()
.max(100, { message: "Description is too long" })
.optional(),
});
type User = z.infer<typeof userSchema>;
export default function Form() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<User>({
resolver: zodResolver(userSchema),
defaultValues: {
name: "Unknown User",
},
});
const onSubmit = (values: User) => {
//只有型別驗證通過,才會執行
console.log(values);
/*
{
"name": "John",
"email": "test@test.com",
"age": 25,
}
*/
// ... 處理表單邏輯
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label htmlFor="name">Name : </label>
<input id="name" type="text" {...register("name")} />
{errors.name && <p>{errors.name.message}</p>}
<label htmlFor="email">Email : </label>
<input id="email" type="email" {...register("email")} />
{errors.email && <p>{errors.email.message}</p>}
<label htmlFor="age">Age : </label>
<input
id="age"
type="number"
{...register("age", { valueAsNumber: true })}
/>
{errors.age && <p>{errors.age.message}</p>}
<label htmlFor="description">Description : </label>
<textarea id="description" type="text" {...register("description")} />
{errors.description && <p>{errors.description.message}</p>}
<button disabled={isSubmitting} type="submit">
{isSubmitting ? "Submitting..." : "Submit"}
</button>
</form>
);
}
Zod 除了一般常見的型別外,也可以針對一些特殊的型別做驗證,像是 email 格式或其他自訂的驗證規則。
以下是範例的欄位說明:
refine
來自訂驗證規則,確保年齡必須是整數且介於 18 到 60 歲之間。驗證規則都可以附加 message
參數,用來定義自訂的錯誤訊息。required_error
和 invalid_type_error
參數則是用來定義必填欄位和無效型別的錯誤訊息。
針對非必填欄位,也可以使用 optional
來設定是否必填。
register
:透過 register 方法來連接 input 欄位與 React Hook Form,使得它能夠追蹤這些欄位的值與錯誤狀態。handleSubmit
:當表單提交時,會根據定義的驗證規則來判斷表單是否有效,並接收傳入的表單資料。formState: { errors, isSubmitting }
:這邊包含表單的各種狀態,errors
用來取得各個欄位的錯誤訊息,isSubmitting
則是用來表示表單是否正在提交中。resolver: zodResolver(userSchema)
:將 Zod 的 schema 傳入作為表單的驗證邏輯。defaultValues
: 用來設定表單初始值,例如範例中的 name
預設為 "Unknown User"
。handleSubmit(onSubmit)
: 若表單通過驗證,才會執行 onSubmit
函式。{...register("欄位名稱")}
:透過 register 方法將 input 欄位與 React Hook Form 連接,實現對欄位值和錯誤狀態的追蹤。valueAsNumber
:會在型別驗證前先把 string 轉成 number。{errors.age && <p>{errors.age.message}</p>}
來動態顯示相應的錯誤資訊。其他更多的說明可以參考 React Hook Form 和 Zod 的文件。