Zodとは?React Hook Formとの連携でバリデーション実装

Zodとは?React Hook Formとの連携でバリデーション実装 React
Zodとは?React Hook Formとの連携でバリデーション実装
この記事は約10分で読めます。

でじぼうです。

TypeScriptのフォーム実装でよく登場する、Zodのバリデーション記述についてまとめました。

でじぼう
でじぼう

この記事は下記の方がおすすめ!

  • Zodってなに?
  • バリデーションはどんな種類があるの?
  • バリデーション実行はどのタイミング?

Zodとは?

Zodとは?React Hook Formとの連携でバリデーション実装をスマートに

Zod(ゾッド)は、TypeScript向けのスキーマバリデーションライブラリです。

簡単に言うと、「このデータはこの形であるべき!」というルールをコードで定義し、そのルール通りになっているかチェックする仕組みです。

特に、ReactやNext.jsなどのフレームワークと組み合わせて使われるReact Hook Formと相性が良く、フロントエンドのフォームバリデーションでよく利用されます。

よく使うバリデーション一覧

下記に、よく利用するZodのバリデーション一覧をまとめました。

チェック内容Zod記述エラーメッセージ
未入力(必須)z.string().min(1, “名前を入力してください”)名前を入力してください
文字数の最小制限z.string().min(3, “3文字以上で入力してください”)3文字以上で入力してください
文字数の最大制限z.string().max(20, “20文字以内で入力してください”)20文字以内で入力してください
メール形式z.string().email(“正しいメールアドレスを入力してください”)正しいメールアドレスを入力してください
正規表現チェックz.string().regex(/^\d+$/, “数字のみで入力してください”)数字のみで入力してください
特定の文字列のみ許可z.enum([“男”, “女”, “未回答”])性別を選択してください
数値の範囲z.number().min(1, “1以上の数値を入力してください”)1以上の数値を入力してください
真偽値のチェックz.boolean().refine(val => val, “同意が必要です”)同意が必要です
日付の存在確認z.date({ required_error: “日付を選択してください” })日付を選択してください
nullを許容z.string().nullable()※nullもOKな項目に使用
オプショナルz.string().optional()※未入力(undefined)もOK

modeの違いとタイミング解説(React Hook Form向け)

React Hook Formでは、いつバリデーションを実行するかを mode で指定できます。

mode設定値タイミングの説明用途例
onSubmitフォーム送信時のみ実行エラー表示を最小限にしたい時
onChange入力のたびに(1文字でも入力すると即時)即時エラー表示が必要な時
onBlurフォーカスが外れたときに実行入力中は集中させたい時
onTouched一度触れてからフォーカスが外れたときに実行初回は控えめ・2回目以降に即バリデーション
allonChange+onBlur+onSubmitすべて実行厳格なバリデーションが必要な場合

下記は、mode: onChange を指定した場合

const {
  register,           // 各フォーム要素にバリデーションを適用するための関数
  handleSubmit,       // フォーム送信時の処理をまとめる関数
  formState: { errors } // バリデーションエラーの状態を管理するオブジェクト
} = useForm({
  mode: "onChange"     // 入力が変わるたびにバリデーションを実行する
});

下記は、mode を省略した場合。デフォルトの onSubmit に設定される

const { 
 register, 
 handleSubmit, 
 formState: { errors }
} = useForm();

実装コード

Zodを使用したバリデーションチェックの実装例をご紹介します。

使用している技術

言語:TypeScript

  • React:UIフレームワーク
  • React Hook Form:フォーム処理ライブラリ
  • Zod:バリデーションスキーマライブラリ
  • zodResolver:ZodとReact Hook Formを接続

実装内容

名前・メールアドレス・電話番号の入力フォームを作成
入力のたびにバリデーションが実行され、間違っていれば即エラーメッセージを表示

  • 未入力チェック(全項目)
  • メールアドレス形式のチェック
  • 電話番号が数字やハイフンのみかを正規表現でチェック
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";

// 入力項目のバリデーションルール
const schema = z.object({
  name: z.string().min(1, "名前を入力してください"),
  email: z
    .string()
    .min(1, "メールアドレスを入力してください")
    .email("正しいメールアドレス形式で入力してください"),
  tel: z
    .string()
    .min(1, "電話番号を入力してください")
    .regex(/^[0-9\-]+$/, "数字またはハイフンのみで入力してください"),
});

// Zodスキーマからフォームの型を自動生成
type FormData = z.infer<typeof schema>;

export default function ContactForm() {
  // useFormでフォームを初期化
  const {
    register, // 各inputにバリデーションを紐づける
    handleSubmit, // フォーム送信時にバリデーションを実行
    formState: { errors }, // 各項目のバリデーションエラー情報
  } = useForm<FormData>({
    resolver: zodResolver(schema), // Zodで定義したスキーマを使う
    mode: "onChange",              // 入力ごとにバリデーション実行
  });

  // バリデーション成功時の処理
  const onSubmit = (data: FormData) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("name")} placeholder="名前" /> // registerの記載でチェック対象とする
      {errors.name && <p>{errors.name.message}</p>}  // エラーメッセージの表示

      <input {...register("email")} placeholder="メールアドレス" />
      {errors.email && <p>{errors.email.message}</p>}

      <input {...register("tel")} placeholder="電話番号" />
      {errors.tel && <p>{errors.tel.message}</p>}

      <button type="submit">送信</button>
    </form>
  );
}

よくあるミスや注意点

  • min(1) だけだと空白(スペース)だけの入力を許してしまう
    .refine(val => val.trim() !== '') を追加すると◎
  • null を許容したい場合は .nullable() を使う
    → 例:z.string().nullable()
    これは null を受け入れ、未入力とは別の扱いになります。
  • zodResolver を使わないとReact Hook Formとの連携ができないので注意

コメント

タイトルとURLをコピーしました