React Hook Form 入門

# はじめに
この記事では、名前入力フォームの実装を通して、 _**[React Hook Form](https://react-hook-form.com/)**_ というReact用のフォーム管理ライブラリの基本的な利用方法についてまとめていきます。

開発環境は以下の通りです。
- React Hook Form v7.43.0
- TypeScript v4.9.5
- React v18.2.0
- Windows11
:::

また、React Hook Form導入前に簡単な名前入力フォームコンポーネントを準備しておきます。
```src/App.tsx
function App() {
  return (
    <form>
      <label htmlFor="name">Name: </label>
      <input type="text" id="name" name="name" placeholder="Input your Name" />
      <input type="submit" />
    </form>
  );
}

export default App;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/f445a0fc-fe76-35d0-554c-b3cac4a61dc5.png)


# インストール
以下のコマンドでReact Hook Fromをインストールします。
```
npm install react-hook-form
```

# register
まずは _**[register](https://react-hook-form.com/api/useform/register)**_ 関数を利用して、最初に作成したコンポーネントでバリデーションやデータ送信など React Hook Form の機能を利用できるようにします。

```src/App.tsx
import { useForm } from "react-hook-form";

function App() {
  const { register } = useForm();

  return (
    <form>
      <label htmlFor="name">Name: </label>
      <input
        type="text"
        id="name"
        {...register("name")}
        placeholder="Input your Name"
      />
      <input type="submit" />
    </form>
  );
}

export default App;
```
registerの戻り値（以下）をinput要素に渡して利用します。

- name
- ref
- onChange
- onBlur

:::note
上記のコードを下記のように書き換えることができます。
```src/App.tsx
import { useForm } from "react-hook-form";

function App() {
  const { register } = useForm();
  const { name, ref, onChange, onBlur } = register("name");

  return (
    <form>
      <label htmlFor="name">Name: </label>
      <input
        type="text"
        id="name"
        name={name}
        ref={ref}
        onChange={onChange}
        onBlur={onBlur}
        placeholder="Input your Name"
      />
      <input type="submit" />
    </form>
  );
}

export default App;
```
:::

:::note
registerの引数 = registerの戻り値のnameになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/8fd9e6aa-e801-81bc-bb0b-5c96724808b5.png)
:::

# handleSubmit
次は、 _**[handleSubmit](https://react-hook-form.com/api/useform/handlesubmit)**_ 関数で入力データを取得します。

```src/App.tsx
import { useForm } from "react-hook-form";

function App() {
  const { register, handleSubmit } = useForm();

  return (
    <form onSubmit={handleSubmit((data) => {
      console.log('data: ', data);
    })}>
      <label htmlFor="name">Name: </label>
      <input
        type="text"
        id="name"
        {...register("name", { required: true })}
        placeholder="Input your Name"
      />
      <input type="submit" />
    </form>
  );
}

export default App;
```
取得できることが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/8d4a0979-be56-7e01-7e6c-c4007c0ba5bd.png)

# バリデーション
次は、入力必須のバリデーションを追加します。
バリデーションは、register関数の第二引数で設定します。引数内で入力必須及びエラーメッセージを設定できます。
また、エラーの判断は _**[formState](https://react-hook-form.com/api/useform/formstate)**_ を利用します。formStateの戻り値のひとつであるerrorsでregister関数の第二引数で設定したエラーメッセージを取得できます。

```src/App.tsx
import { useForm } from "react-hook-form";

function App() {
  const { register, handleSubmit, formState: { errors } } = useForm();
  console.log("errors: ", errors);

  return (
    <form
      onSubmit={handleSubmit((data) => {
        console.log("data: ", data);
      })}
    >
      <label htmlFor="name">Name: </label>
      <input
        type="text"
        id="name"
        {...register("name", { required: "Please Input your Name" })}
        placeholder="Input your Name"
      />
      <input type="submit" />
    </form>
  );
}

export default App;
```
エラーメッセージが表示されることを確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/12133cdb-e470-e82d-ec63-74fffc417ca7.png)

# デフォルト値
次は、デフォルト値を設定します。デフォルト値は、useFormの引数に設定します。
```src/App.tsx
import { useForm } from "react-hook-form";

function App() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm({ defaultValues: { name: "Mike" } });
  console.log("errors: ", errors);

  return (
    <form
      onSubmit={handleSubmit((data) => {
        console.log("data: ", data);
      })}
    >
      <label htmlFor="name">Name: </label>
      <input
        type="text"
        id="name"
        {...register("name", { required: "Please Input your Name" })}
        placeholder="Input your Name"
      />
      <input type="submit" />
    </form>
  );
}

export default App;
```
デフォルト値が設定されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/8187305f-818c-899b-00cf-aec9096b8903.png)

:::note
デフォルト値を設定しておくと、register関数の引数を誤った値にした時にTypeScriptがエラーを出してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/65d7830f-23cc-8225-1479-a47ccc7ac96e.png)
:::

# watch
最後に _**[watch](https://react-hook-form.com/api/useform/watch)**_ 関数を利用して、入力値をリアルタイムで表示します。
引数にinputのnameを渡すと、対象のinputの値を取得します。引数を渡さなければ、全ての値を取得します。

```src/App.tsx
import { useForm } from "react-hook-form";

function App() {
  const {
    register,
    handleSubmit,
    watch,
    formState: { errors },
  } = useForm({ defaultValues: { name: "" } });
  console.log("errors: ", errors);
  const name = watch("name");

  return (
    <form
      onSubmit={handleSubmit((data) => {
        console.log("data: ", data);
      })}
    >
      <label htmlFor="name">Name: </label>
      <input
        type="text"
        id="name"
        {...register("name", { required: "Please Input your Name" })}
        placeholder="Input your Name"
      />
      <p>{name}</p>
      <input type="submit" />
    </form>
  );
}

export default App;
```

入力値をリアルタイムで表示させることができました。
![ezgif-4-452d92e941.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/cc18e704-c585-afdd-f5a8-9236b7bb4a67.gif)

# 最後に
名前入力フォームの実装を通してReact Hook Form の基本的な利用方法についてまとめてみました。導入は順調にできたので、より細かな部分も今後学んでいければと思っています。
最後までお読みいただきありがとうございました！


# 参照
- [React Hook Form](https://react-hook-form.com/)