はじめに
現在TypeScript×Next.js×Rails APIでSNSアプリを作成しています。
ユーザー名の重複チェックをフロント側でできないだろうか、とググっていた時にreact-hook-form×yupで実装できるようなのでやってみました。
yupとは
バリデーションチェックのためのライブラリです。
スキーマを定義して、バリデーションのルールや表示するエラーメッセージを自由に設定・適用できます。
手順
入力値に対してバリデーションを実行するスキーマを定義し、バリデーションをカスタマイズしていきます。
react-hook-formとyupの統合にはResolver
を使います。
これらを踏まえて作成したサンプルコードは下記です。
※入力項目は複数ありますが、ユーザー名の処理のみ抜粋
page.tsx
interface IFormInput {
username: string;
}
// バリデーションスキーマを定義
const postSchema = yup.object().shape({
username: yup
.string()
.required(`ユーザー名は必須です`)
.test("sameusername", "ユーザー名が重複しています", async (input) => {
const response = await getPosts();
return !response.some((post: any) => post.username === input);
}),
});
export default function Page() {
const router = useRouter();
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm<IFormInput>({
resolver: yupResolver(postSchema), // yupを使ったバリデーションを設定
});
//(バックエンドとの連携部分)
const postPostFunc = async (post: IFormInput) => {
await postPost(post);
if (router) {
router.push("/posts");
}
};
const onSubmit: SubmitHandler<IFormInput> = async (data) => {
postPostFunc(data);
reset();
};
return (
<div>
<h2 className="text-2xl font-bold text-indigo-800 dark:text-white mb-4">
投稿作成
</h2>
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label className="block mb-2 text-indigo-500">ユーザー名</label>
<input
className="w-full p-2 mb-2 text-indigo-700 border-b-2 border-indigo-500 outline-none focus:bg-gray-300"
type="text"
{...register("username")}
/>
{errors.username && (
<p className="text-red-500">{errors.username.message}</p>
)}{" "}
</div>
<button
className="w-full bg-indigo-700 hover:bg-pink-700 text-white font-bold py-2 px-4 mb-6 rounded"
type="submit"
disabled={Object.keys(errors).length > 0} // エラーがある場合は無効化
>
投稿
</button>
</form>
</div>
);
}
おわりに
今回yupの存在を初めて知りました。
最初はバックエンドでもバリデーションを実装して。。みたいな流れも考えていましたが、フロント側で完結できるのがありがたかったです。
参考