React Hook Form

実務で、React Hook FormとYupを使ったバリデーション付きフォームを実装したので、
備忘録として残したいと思います。

まず、React Hook FormとはReactでフォームを簡単に扱うことができるライブラリです。
（詳細は割愛いたします:bow:）

https://react-hook-form.com/

本記事では、React Hook FormとYupを組み合わせて、シンプルなバリデーション付きフォームを作成する方法を記載します。

---

### 全体の流れ

1. **Yupでバリデーションルールを定義**
    `yup`を使ってフォームの入力値に対するバリデーションを定義
    
2. **React Hook Formでフォームを管理**
    `useForm`フックを使って、フォームの状態やバリデーションエラーを管理
    
3. **YupのスキーマをReact Hook Formに適用**
    `yupResolver`を使って、React Hook FormにYupスキーマを紐付け
    
4. **入力項目に`register`を割り当てる**
    React Hook Formの`register`関数を使って、フォームの各フィールドを紐付け

5. **`handleSubmit`でフォーム送信処理**
    バリデーションを通過した場合にのみ送信処理を実行
    

---

### **1. Yupでバリデーションルールを定義する**

まず、Yupを使ってフォームのバリデーションルールを定義します。

ここでは簡単に名前とメールアドレスを入力するだけのフォームとします。

```tsx
import * as yup from "yup";

const formSchema = yup
  .object({
    name: yup.string().required("名前を入力してください"),
    email: yup
      .string()
      .email("有効なメールアドレスを入力してください")
      .required("メールアドレスを入力してください"),
  })
  .required();

export type FormValues = yup.InferType<typeof formSchema>;
```

このスキーマでは以下をチェックします

- `name`: 空欄ではないこと
- `email`: 有効なメールアドレス形式であること、および空欄ではないこと

**yup.InferTypeについて**
- Yupで定義されたバリデーションスキーマ（`formSchema`）を元にして、TypeScriptの型定義（`FormValues`）を生成
- Yupスキーマで定義したフィールド名やデータ型が、TypeScriptの型定義に自動的に反映されるため、スキーマと型定義の間で不整合が起きるリスクを防ぐことができる


### **2. React Hook Formでフォームを管理する**

次に、`useForm`を使ってフォームの状態管理とバリデーションを設定します。

```tsx

import React from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";

const formSchema = yup
  .object({
    name: yup.string().required("名前を入力してください"),
    email: yup
      .string()
      .email("有効なメールアドレスを入力してください")
      .required("メールアドレスを入力してください"),
  })
  .required();

export type FormValues = yup.InferType<typeof formSchema>;

const MyForm = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<FormValues>({
    resolver: yupResolver(formSchema), // Yupのスキーマを紐付ける
    defaultValues: { name: "", email: "" }, // 初期値の設定
  });

  const onSubmit = (data: FormValues) => {
    console.log("フォームデータ:", data);
    // dataには、registerで紐付けたフォームフィールド（nameとemail）の入力値が格納される。
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label>名前:</label>
        <input {...register("name")} />
        {errors.name && <p>{errors.name.message}</p>} {/* バリデーションエラーの表示 */}
      </div>

      <div>
        <label>メールアドレス:</label>
        <input {...register("email")} />
        {errors.email && <p>{errors.email.message}</p>} {/* バリデーションエラーの表示 */}
      </div>

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

export default MyForm;

```
### **フォーム**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936887/59b356ad-6143-3142-36dc-c73d5a642763.png)


### **ポイント解説**

### **1. `useForm`とは？**

`useForm`は、React Hook Formが提供する**フォーム管理のメインフック**です。フォーム全体を管理するための設定や関数、状態を取得できます。

### **使い方**

以下のように`useForm`を呼び出すことで、フォームの管理に必要な機能をまとめて取得できます。

```tsx
const {
  register,
  handleSubmit,
  formState: { errors },
} = useForm<FormValues>({
  resolver: yupResolver(formSchema),
  defaultValues: { name: "", email: "" },
});

```

### **主な設定オプション**

- **`resolver`**:
    バリデーションを外部ライブラリ（Yupなど）に委託するための設定。ここでは、`yupResolver`を使い、Yupスキーマに基づいたバリデーションを行っている
    
    
- **`defaultValues`**:
    各フィールドの初期値を設定。この例では`name`と`email`の初期値を空文字列（`""`）にしている
    

### **2.`register`とは**

`register`は、**各フォームフィールドをReact Hook Formに登録**するための関数です。これを使って、フォームの入力値や状態をReact Hook Formで管理できるようにします。

### **使い方**

以下のように、フォーム要素に`register`を適用します：

```tsx

<input {...register("name")} />
<input {...register("email")} />

```

ここで渡す引数（例：`"name"`）は、フォームデータ内のフィールド名を指定します。これにより、React Hook Formがそのフィールドを認識し、管理対象とします。

### **機能**

- 入力値の監視と取得：ユーザーが入力した値をリアルタイムで管理
- バリデーションの紐付け：`resolver`で設定したスキーマに基づいて入力値を検証する


### **3. `handleSubmit`とは？**

`handleSubmit`は、フォームの送信時にバリデーションを実行し、成功時に指定した関数（`onSubmit`）を呼び出すための関数です。

### **使い方**

フォームの`onSubmit`イベントに以下のように設定します：

```tsx
<form onSubmit={handleSubmit(onSubmit)}>

```

### **動作の流れ**

1. **フォームが送信される**：ボタンを押すことで、`onSubmit`イベントが発火
2. **バリデーションの実行**：`resolver`で指定したYupスキーマに基づいて入力値が検証される
3. **成功時（バリデーション通過時）**：
    - `onSubmit`関数が実行され、検証済みの入力データ（`data`）が引数として渡される
4. **失敗時（バリデーションエラー発生時）**：
    - エラー情報が`formState.errors`に格納される


```jsx
 const onSubmit = (data: FormValues) => {
    console.log("フォームデータ:", data);
    // registerで紐付けたフォームフィールド（nameとemail）の入力値が格納される。
    // 実際にはAPIの処理などが入る。
  };
```

### **4. `formState.errors`とは？**

`formState.errors`は、**バリデーションエラーの状態を管理するオブジェクト**です。

各フィールドごとにエラー情報を格納し、ユーザーにエラー内容を表示する際に利用します。

### **使い方**

```tsx
{errors.name && <p>{errors.name.message}</p>}
```

- `errors.name`: `name`フィールドに対するエラー情報を持っている
- `errors.name.message`: エラーメッセージ（Yupスキーマで指定した文言）が格納されている

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936887/72e89929-3c72-ae7e-61e1-9e7138276cf4.png)


### **コード全体の流れ**

1. **フォームの管理を`useForm`でセットアップ**
    - `useForm`でフォームの初期値やバリデーションを設定
    - 各フィールドを`register`で登録
2. **フォーム送信時に`handleSubmit`でバリデーション実行**
    - バリデーションを通過した場合、`onSubmit`関数が呼び出される
    - エラーがある場合は、`formState.errors`にエラー情報が格納される
3. **エラーがあればユーザーに表示**
    - 各フィールドごとに`errors`をチェックし、エラーメッセージを表示

※完成したフォーム

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936887/6d0a4163-b494-676a-541c-df93cb97c46b.png)