第九章:拯救你的表單地獄 - React Hook Form 與 Zod 的終極防禦
在任何一個管理後台系統中,除了顯示資料的表格 (Table) 之外,最常做的事情就是讓使用者填寫表單 (Form)。例如:「新增員工資料」、「修改打卡時間」、「設定系統參數」。
如果你曾經自己用傳統的 React useState 來寫表單,你一定經歷過這場惡夢:
你要為每個輸入框寫一個 onChange 函數,你要手動檢查「這個 Email 有沒有打錯?這個密碼是不是大於 8 碼?」如果使用者打錯了,你還要手動設定紅色的錯誤訊息,然後在畫面重新渲染。如果表單有 10 個欄位,你的程式碼會輕易突破 300 行,而且每次打字都會導致整個畫面卡頓 (因為一直觸發重新渲染)。
這就是為什麼業界開發出了表單的終極武器組合。
🎯 本章目標
- 認識業界效能最強、最輕量的表單管理套件:React Hook Form (RHF)。
- 認識讓前端工程師不再頭痛的資料驗證 (Schema Validation) 套件:Zod。
- 讓 AI 幫我們把這兩者完美結合,寫出一個防呆做到極致、效能極佳的「新增員工表單」。
🛡️ 什麼是 React Hook Form 與 Zod?
- React Hook Form:負責管理表單的狀態。它的特色是採用「非受控元件 (Uncontrolled Components)」的技術,這意味著你在打字時,網頁不會每打一個字就重新渲染,效能好到無可挑惕。
- Zod:負責定義「規則」。你可以用非常像白話文的語法告訴 Zod:「我規定姓名必須是字串,且長度最少 2 個字;信箱必須符合標準 Email 格式。」Zod 就像一個嚴格的警衛,只有全部符合規則的資料,才能通過它的審查。
🔥【Vibe Prompt 實戰咒語】
我正在開發 React 專案。我需要做一個「新增員工」的精美表單。1. 請給我 npm 安裝 react-hook-form, zod, 以及 @hookform/resolvers 的指令。2. 請在元件中定義一個 Zod Schema,包含防呆錯誤訊息:- name (字串,必填,最少 2 個字,否則提示 "名字太短")- email (字串,必須是合法的 Email,否則提示 "信箱格式錯誤")- department (下拉選單,選項為 "工程部" 或 "行銷部")3. 請使用 useForm 與 zodResolver 將表單綁定在一起。4. UI 請使用 Tailwind CSS,要有圓角、陰影,並垂直排列 (space-y)。5. 如果使用者亂填就按送出,請在該 Input 欄位的正下方,顯示紅色的錯誤訊息文字。
AI 會教你安裝這些黃金組合:
npm install react-hook-form zod @hookform/resolvers
並且生成極度優雅且防護嚴密的元件程式碼:
// 📂 src/components/EmployeeForm.tsx
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
// 1. 定義嚴格的防呆規則 (Schema) 與報錯文字
const employeeSchema = z.object({
name: z.string().min(2, { message: "名字至少要 2 個字喔!" }),
email: z.string().email({ message: "這看起來不像信箱格式喔!" }),
department: z.enum(["工程部", "行銷部"], {
errorMap: () => ({ message: "請選擇一個部門" })
}),
});
// 使用 TypeScript 自動從 Zod 規則推導出型別 (超方便!)
type EmployeeFormValues = z.infer<typeof employeeSchema>;
export default function EmployeeForm() {
// 2. 啟動 React Hook Form,並請 Zod 警衛來把關
const {
register, // 用來把 Input 註冊給 RHF 管
handleSubmit, // 用來攔截原本的 form 送出事件
formState: { errors } // 這裡面裝著所有即時的錯誤訊息
} = useForm<EmployeeFormValues>({
resolver: zodResolver(employeeSchema),
});
// 3. 只有當資料 100% 符合規則時,才會進到這個函數!
const onSubmit = (data: EmployeeFormValues) => {
console.log("成功送出,準備打 API:", data);
alert(`新增成功:${data.name}`);
};
return (
<div className="max-w-md mx-auto bg-white p-8 rounded-2xl shadow-sm border border-slate-100">
<h2 className="text-xl font-bold mb-6 text-slate-800">新增員工資料</h2>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-5">
{/* 姓名欄位 */}
<div>
<label className="block text-sm font-medium text-slate-700 mb-1">姓名</label>
<input
{...register("name")}
className="w-full border border-slate-300 rounded-lg p-2 focus:ring-2 focus:ring-blue-500 outline-none"
placeholder="請輸入真實姓名"
/>
{/* 錯誤顯示區塊:只有出錯時才會顯示紅字 */}
{errors.name && <p className="text-red-500 text-sm mt-1">{errors.name.message}</p>}
</div>
{/* Email 欄位 */}
<div>
<label className="block text-sm font-medium text-slate-700 mb-1">電子信箱</label>
<input
{...register("email")}
className="w-full border border-slate-300 rounded-lg p-2 focus:ring-2 focus:ring-blue-500 outline-none"
placeholder="example@company.com"
/>
{errors.email && <p className="text-red-500 text-sm mt-1">{errors.email.message}</p>}
</div>
{/* 提交按鈕 */}
<button
type="submit"
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-lg transition-colors"
>
儲存資料
</button>
</form>
</div>
);
}
💼 [商業應用場景] 為什麼前端的防呆這麼重要?
如果你不加 Zod 防呆,讓使用者亂填了一堆空白的名字、或是根本沒有 @ 的信箱,這筆爛資料就會送到後端 (FastAPI)。
後端當然也會檢查,然後後端會報錯,把錯誤訊息傳回前端,前端再顯示出來。
這個過程叫做「伺服器端驗證 (Server-side Validation)」。它浪費了網路傳輸的時間,也浪費了伺服器的算力。
一個專業的軟體公司,會做到「前後端雙重驗證」。 前端利用 Zod,在使用者根本還沒發出 API 之前,就在他的瀏覽器端用極快的速度把他擋下來,告訴他「你信箱打錯了喔」。這不僅節省了伺服器成本,還能給使用者「即時的回饋感」,這就是你系統好用、客戶願意續約的關鍵秘密!
✅ 本章小結
這套 React Hook Form + Zod 的黃金組合,已經是目前全端開發的「終極答案」。
它徹底改變了過去前端寫表單的痛苦生態。學會這招,未來不管是面對幾十個欄位的「進階過濾器」,還是多重步驟的「結帳問卷系統」,你都能像切豆腐一樣輕鬆秒殺!