React Hook Formを使ってフォームを実装してみる

# **React Hook Formとは**
**React Hook Form**は、Reactで簡単にフォームを作成・管理できるライブラリです。
従来のフォームライブラリと異なり、Reactのフックを利用しているため、フォームの状態管理やバリデーションを、シンプルなコードで管理することができます。
今回は、React Hook Formを使いバリデーションを設定した簡単なフォームを作成します。
各ファイルを確認したい方は[こちら](https://github.com/toumachan/react-hook-form)から

# 実装方法
## 1, ライブラリのインストール
まずは、React Hook Formを利用するために、以下のコマンドを実行し、ライブラリをインストールします。
```javascript
npm install react-hook-form
```

## 2, フォームの型宣言
フォームで扱うデータの型を定義します。TypeScriptを利用することで、型安全な開発を実現できます。
```react
interface FormData {
  name: string;
  email: string;
  gender: 'male' | 'female';
  memo: string;
  country: string;
  agreeToTerms: boolean;
}
```

## 3, useFormの宣言

`useForm`フックからメソッドを呼び出します。
最低限必要なメソッドは、`register`と`handleSubmit`です。

- `register`: 各フォームフィールドに対する登録関数。これにより、フォームフィールドがReact Hook Formによって管理されるようになります
- `handleSubmit`: フォームが送信されたときに呼び出される関数。これをフォームの`onSubmit`イベントハンドラとして使用します

今回はエラーメッセージを設定したいので、`formState`も記述しています。
```react
const { register, handleSubmit, formState: { errors } } = useForm();
```

### useFormのオプション引数

`useForm`フックには、デフォルト値やバリデーションルールなどを設定するためのオプション引数を設定することができます。

- `mode`: バリデーションが実行されるタイミングを設定します
    - `onSubmit`：送信イベントでトリガーされる
    - `onBlur`：フォームからフォーカスが離れたときにトリガーされる
    - `onTouched`：フォームからフォーカスが離れたときにトリガーされる
    - `onChange`：入力の度にトリガーされる
- `defaultValues`: 入力のデフォルト値を設定します
```react
const defaultValues: FormData = {
  name: '山田太郎',
  email: 'admin@example.com',
  gender: 'male',
  memo: '',
  country: '',
  agreeToTerms: false
};

const { register, handleSubmit, formState: { errors } } = useForm({
  defaultValues,
  mode: 'onChange'
});
```

## 4, registerを使ってFormを管理する

`register`関数を使用して、フォーム要素とReact Hook Formを紐付けます。
フォーム要素のタグ内にregister関数を使った記述をすることで、その要素をReact Hook Formで管理できるようになります。

- 第1引数：参照の名前を登録する（必須）
- 第2引数：バリデーションのルールをオブジェクト形式で設定します
```react
<input id='name' type="text"
  {...register('name', {
    required: '名前は必須入力です。',             // 必須入力
    maxLength: {                             // バリデーション設定
      value: 20,                             // 最大文字数
      message: '名前は20文字以内にしてください。'   // エラーメッセージ
    }
  })}
/>
```

## 5, エラーメッセージを設定する

`errors`オブジェクトを使用して、各フォーム要素に対するエラーメッセージを表示します。
```react
<div className='errorMessage'>{errors.name?.message}</div>
```

## 6, **handleSubmitでフォームを送信する**

`handleSubmit`関数を使用して、フォーム送信時の処理を定義します。
今回は、送信時コンソールに送信内容を表示します。
```react
const onSubmit = (data: FormData) => {
  console.log(data);
};
```

## 7, おまけ

最後に必須項目が入力されていないと送信ボタンが押せないように、必須項目が未入力の場合は送信ボタンを「無効」に設定します。
`formState`に`isValid`を設定します。
```react
const { register, handleSubmit, formState: { errors, isValid } } = useForm({
  defaultValues,
  mode: 'onChange'
});
```
isValidがfalseの時は送信ボタンを無効とします。
```react
<button type='submit' className='submitButton' disabled={!isValid}>送信</button>
```

# Zodを使ったバリデーション設定

React Hook Formでは、ライブラリを使用することで、より高度で複雑なバリデーションを設定することができます。
今回は、Zodを使って、前述と同じバリデーションを実装してみます。
Zodはtypescriptの型システムを活用して、フォームの入力値などアプリケーションで扱うデータが、宣言したスキーマに沿っているかを検証することができます。

## 1, Zodのインストール
```javascript
npm install zod
```

## 2, Zodによるスキーマ定義

Zodを使用して、フォームデータのスキーマを定義します。型安全なバリデーションを実現するために、各フィールドの型、必須項目、値の範囲などを厳密に定義します。
```react
const schema = z.object({
  name: z.string().nonempty('名前は必須入力です。').max(20, '名前は20文字以内にしてください。'),
  email: z.string().nonempty('メールアドレスは必須入力です。').email('メールアドレスの形式が不正です。'),
  gender: z.enum(['male', 'female']),
  memo: z.string().min(10, '備考は10文字以上にしてください。'),
  country: z.string().nonempty('国は必須選択です。'),
  agreeToTerms: z.boolean().refine(val => val, '利用規約に同意してください。')
});
```

## 3, React Hook Formの初期化

`resolver` プロパティ、`zodResolver` を使って `zod` スキーマを `react-hook-form` に統合しています。これにより、フォームのバリデーションが `zod` のスキーマに基づいて行われます。
```react
const { register, handleSubmit, formState: { errors, isValid } } = 
useForm<FormData>({
  resolver: zodResolver(schema),
  defaultValues,
  mode: 'onChange'
});
```

## 4, フォーム要素の管理

`zod` を使用してバリデーションスキーマを設定した場合、`react-hook-form` の `resolver` プロパティを介して `zod` のバリデーションが自動的に適用されるため、`<input>` 要素の登録時に追加のバリデーションロジックを書く必要がなくなります。
```react
<input id='name' type="text"
　　{...register('name')}
/>
```

# 参考記事
https://qiita.com/hinako_n/items/06f536d2d130712cc76c
https://qiita.com/Nozomuts/items/60d15d97eeef71993f06

# まとめ
 Zodを使ったバリデーション設定にはもっと高度なものがあるようですが、一旦今の自分に必要ないかなと思ったので、このくらいにしておきます（ただめんどくさくなっただけです）。
また必要になる機会や、実際の業務で使用した場合は記載していこうと思います。