src/PATH/TO/YOUR/COMPONENT/validations/userNameSchema.ts
import { z } from "zod"
import debounce from "lodash/debounce"
/**
* ユーザー名がユニークかどうかを検証する
*/
const isUserNameUnique = async (userName: string): Promise<boolean> => {
// TODO: 実際の検証ロジックを書くこと
console.log(`● isUserNameUnique (${userName})`)
await new Promise((resolve) => setTimeout(resolve, 500))
return userName === "aaaaa" ? false : true
}
/**
* ユーザー名がユニークかどうかを検証する(debounced)
*/
const debouncedIsUserNameUnique = debounce(isUserNameUnique, 500)
/**
* userName 入力時に検証するスキーマ
*/
const inputValidationSchema = z
.string()
.min(5, { message: "ユーザー名は最低5文字必要です。" })
.max(15, { message: "ユーザー名は最大15文字です。" })
.refine((userName) => /^[A-Za-z0-9_]+$/.test(userName), {
message: "ユーザー名には文字、数字、アンダースコア(_)のみ使用できます。",
})
export const userNameSchema = z.object({
userName: inputValidationSchema.refine(
async (userName) => {
// 「ユーザー名がユニークかどうかの検証」前のバリデーションでエラーがある場合は true を返して中断してこのバリデーションエラーは表示させない
const result = inputValidationSchema.safeParse(userName)
if (!result.success) return true
// ユーザー名がユニークかどうかを検証する
const isUnique = await debouncedIsUserNameUnique(userName)
return isUnique ? true : false
},
{
message: "このユーザー名は既に使用されています。",
},
),
})
export type UserNameSchema = z.infer<typeof userNameSchema>
コンポーネントでは特別に処理を書く必要はありません
MyComponent.tsx
// react-hook-form
const formOptions = {
resolver: zodResolver(userNameSchema),
}
const {
register,
formState: { errors },
handleSubmit,
} = useForm<UserNameSchema>(formOptions)
const onSubmit: SubmitHandler<UserNameSchema> = (data) => {
console.log(data)
}