✉️
【VeeValidate × Zod】refine/superRefineがうまく動かないときの解決策
VeeValidate × Zod
でフォームを作成する際、例えば、メールアドレスを再度確認のために入力してもらう場面など、refine/superRefine
を利用することがあると思われます。
例えば、こんな感じです。
画面イメージ
Validation
発火時
コード
export const schema = toTypedSchema(
z
.object({
name: z
.string({
required_error: errorMessage.name_empty,
})
.nonempty(errorMessage.name_empty), // 注:別の項目
email: z
.string({
required_error: errorMessage.email_empty,
})
.nonempty(errorMessage.email_empty)
.email(errorMessage.email_check),
emailConfirm: z
.string({
required_error: errorMessage.email_empty,
})
.nonempty(errorMessage.email_empty)
.email(errorMessage.email_check)
// 注:この下にも他のValidation項目が続きます。
})
.superRefine(({ email, emailConfirm }, ctx) => { // 問題のメールの再確認
if (email !== emailConfirm) {
ctx.addIssue({
path: ["emailConfirm"],
code: "custom",
message: errorMessage.email_confirm,
});
}
}),
);
ところが、このメールのチェック、他のすべてのValidation
が解決した後でないと、発火してくれません。
それは、VeeValidate
の公式のZod Schema Validationに、以下のような記述がある通りです。
こちらが問題のissueです。
これは困ったなあと思い、調べたところ、偉大な先人がいらっしゃいまして、解決策がありました。
Zod
の公式のissueです。
他にも多数の解決策がありましたが、Zod
の場合、一番当てはめやすかったので、こちらの解決策を選んでみました。
先ほどのコード例でしたら、以下の通り書き直すと、他Validation
と同様のタイミングで発火してくれます。
export const schema = toTypedSchema(
z.object({
form: z.object({
name: z
.string({
required_error: errorMessage.name_empty,
})
.nonempty(errorMessage.name_empty),
// 注:この下にも他のValidation項目が続きます。
}),
formMail: z // メール系のschemaを分離して解決します。
.object({
email: z
.string({
required_error: errorMessage.email_empty,
})
.nonempty(errorMessage.email_empty)
.email(errorMessage.email_check),
emailConfirm: z
.string({
required_error: errorMessage.email_empty,
})
.nonempty(errorMessage.email_empty)
.email(errorMessage.email_check),
})
.refine(({ email, emailConfirm }) => email === emailConfirm, {
path: ["emailConfirm"],
message: errorMessage.email_confirm,
}),
}),
);
いやあ、本当にありがたや。ありがたや。
もし、他にも同じ事象でお困りの方がいらっしゃいましたら、何かのご参考になれば幸いです。
最後までお読み頂き、ありがとうございました。
Discussion