React Hook Form(Zodで型推論)Notionクローンアプリの認証、フォーム送信で実装

React Hook Form は、Reactでフォームを扱うためのライブラリです

https://react-hook-form.com

フォームの入力内容はuseStateで管理しない

通常フォームの入力内はuseStateで入力内容変更のたびに再レンダリングされて、いつでもアクセス可能な値として管理してます。

React Hook Formは入力時に再レンダリングせず、送信時にrefでDOMから値を取得します

React Hook Formは非制御コンポーネントからどうやって変更を検知しているのか – commmune Engineer Blog

(途中で値を取得したい場合は、そのように記述することも可能)

主要な機能

register、handleSubmit,、formStateこの3つはreact-hook-formで最も基本的で頻繁に使用される機能です。

register

inputやtextareaなどのフォーム要素をreact-hook-formに「登録」して、値の管理バリデーションを任せる機能

handleSubmit

フォームで下記のように書くとonSubmit()をコールする前にバリデーションをして、OKであれば実行します

<form onSubmit={handleSubmit(onSubmit)}>

onSubmit={…} ← これはHTML属性
onSubmit ← これは自分で定義した関数名

名前が同じで紛らわしいですが、たまたま慣習的に同じ名前を使っているだけです。

handleSubmit(onSubmit)

  1. フォーム送信イベントをキャッチ
  2. event.preventDefault() を実行(ページリロード防止)
  3. 全フィールドのバリデーション実行
  4. エラーがあれば → onSubmitは呼ばれない
  5. エラーがなければ → onSubmit(data) を実行

formState

フォームの現在の状態(エラー、送信中、タッチ済みなど)を取得できるオブジェクトです。

よく使うプロパティ

typescript

const { 
  errors,        // バリデーションエラー
  isValid,       // 全フィールドが有効か
  isSubmitting,  // 送信処理中か
  isDirty,       // 初期値から変更されたか
  isSubmitted,   // 送信が完了したか
  touchedFields  // フォーカスされたフィールド
} = formState;

バリデーション機能

Zodを使用したバリデーション

Zodとはデータのバリデーションと型定義を同時に行えるライブラリ です。

Zodの基本的な使用方法

z.object() でスキーマを作り、parse() でデータを検証します。
エラーがある場合は例外を投げ、正しい場合のみ安全に型付きデータとして返します。

またz.infer で Zodのスキーマ型推論もできます

型推論とは、プログラマが型を明示的に書かなくても、コンパイラが自動的に型を判定してくれる機能

↓エディターでホバーすると型の確認できます(これは型推論ではなく普通に明示的にFCと型指定されてます)

zodResolverでReact hook formとZodを連携

React Hook Form がフォーム送信時に呼び出す「バリデーション処理」を、
Zod のスキーマを使って実行できるようにする関数 です。

React Hook Formのみ(register内でバリデーション定義)

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

  const onSubmit = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        {...register("email", {
          required: "メールアドレスは必須です",
          pattern: {
            value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
            message: "有効なメールアドレスを入力してください",
          },
        })}
      />
      {errors.email && <p>{errors.email.message}</p>}
      <button type="submit">送信</button>
    </form>
  );
}

React Hook Form + Zod

const schema = z.object({
  email: z.string().nonempty("メールアドレスは必須です").email("有効なメールアドレスを入力してください"),
});

export function RHFZodForm() {
  const { register, handleSubmit, formState: { errors } } = useForm({
    resolver: zodResolver(schema),
  });

  const onSubmit = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("email")} />
      {errors.email && <p>{errors.email.message}</p>}
      <button type="submit">送信</button>
    </form>
  );
}

「Zod」を使用したスキーマの例
https://ics.media/entry/240611