React 表單與校驗提示詞(React Hook Form + Zod:前後端共用校驗規則、聯動字段、錯誤提示與提交狀態)
用 React 做註冊、下單、資料編輯這類表單,字段多、有聯動校驗、還要和後端校驗保持一致時用:描述字段和規則,得到用 Zod 定義校驗規則、React Hook Form 管理表單狀態的完整代碼,包括跨字段校驗、後端錯誤回填和無障礙的錯誤提示。
通用大模型 對話模型通用
你是一名熟悉 React Hook Form 和 Zod 的前端工程師。請幫我實現一個表單。 - 表單用途:[如企業開票資料填寫] - 字段與規則(字段名、類型、是否必填、格式要求): [字段與規則] - 字段之間的聯動:[字段之間的聯動](例:選擇「企業」時稅號必填,選擇「個人」時隱藏稅號) - 提交接口與可能的錯誤返回:[提交接口與可能的錯誤返回](例:POST /api/invoices,返回字段級錯誤) - UI 組件庫:[UI 組件庫](例:shadcn/ui、Ant Design、原生元素) - 是否需要與後端共用校驗規則:[是/否] 要求: 1. 用 Zod 定義校驗規則,並從規則推導出 TypeScript 類型,不要重複手寫類型。 2. 錯誤提示用中文,具體到如何修正(例如「稅號應為 15 到 20 位字母或數字」,而不是「格式錯誤」)。 3. 聯動校驗:跨字段規則(如條件必填、兩次密碼一致、結束日期晚於開始日期)放在整體校驗中,並把錯誤掛到具體字段上;被隱藏的字段不參與校驗。 4. 表單狀態:校驗的觸發時機(失去焦點時校驗,提交後改為輸入時實時校驗);提交中禁用按鈕,防止重複提交;提交成功後的處理。 5. 後端錯誤:把接口返回的字段級錯誤回填到對應字段,把非字段錯誤顯示在表單頂部。 6. 無障礙:每個輸入框關聯標籤;錯誤訊息通過屬性關聯到輸入框,並標記字段為無效;提交失敗後焦點移到第一個出錯的字段。 7. 如果需要與後端共用:說明如何把校驗規則放到共享模組中,後端用同一份規則再校驗一次(前端校驗只為體驗,後端校驗才是安全保障)。 輸出:校驗規則文件、表單組件代碼、一份測試(至少覆蓋必填、聯動必填、後端錯誤回填),代碼帶中文註釋。
高亮處換成你自己的內容:[如企業開票資料填寫]、[字段與規則]、[字段之間的聯動]、[提交接口與可能的錯誤返回]、[UI 組件庫]、[是/否]
ChatGPT Plus 充值
已被複製 0 次
使用說明
怎麼填變量:[字段與規則] 盡量寫全,包括格式和長度。[字段之間的聯動] 是表單中最容易出錯的部分,比如「選了企業才顯示稅號」,要寫清楚隱藏時是否清空、是否校驗。
常見坑:
- 只做前端校驗。前端校驗可以被繞過,後端必須用同樣的規則再校驗一次。用 Zod 的好處之一,就是可以前後端共用同一份規則。
- 被隱藏的字段仍然參與校驗,導致用戶看不到錯誤卻無法提交。
- 錯誤提示寫「格式錯誤」「輸入有誤」,用戶不知道該怎麼改。
追問技巧:追問「把這個表單拆成三步的分步表單,每一步只校驗當前步驟的字段」,或「加上草稿自動儲存,刷新頁面後恢復已填寫的內容」。
示例輸出
示例,僅供參考(校驗規則節選)
ts
import { z } from 'zod'
export const invoiceSchema = z
.object({
type: z.enum(['company', 'personal']),
title: z.string().trim().min(1, '請填寫發票抬頭').max(100, '發票抬頭不超過 100 個字'),
taxId: z.string().trim().optional(),
email: z.string().email('請填寫正確的電郵,用於接收電子發票'),
})
.superRefine((v, ctx) => {
if (v.type === 'company' && !/^[A-Z0-9]{15,20}$/i.test(v.taxId ?? '')) {
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['taxId'], message: '稅號應為 15 到 20 位字母或數字' })
}
})
export type InvoiceForm = z.infer<typeof invoiceSchema>
後端錯誤回填:
ts
const onSubmit = async (data: InvoiceForm) => {
const res = await fetch('/api/invoices', { method: 'POST', body: JSON.stringify(data) })
if (!res.ok) {
const { fieldErrors } = await res.json()
for (const [name, message] of Object.entries(fieldErrors ?? {})) {
setError(name as keyof InvoiceForm, { message: String(message) })
}
}
}同款作品
用這條提示詞做出來的作品;原作者會因此獲得積分
還沒有同款,來做第一個。


0 條評論
還沒有評論,來搶沙發~