react-hook-formを使った場合と使わない場合を比べてみた

## react-hook-formとは？

React Hook Formは、Reactアプリケーションでフォームを簡単に扱うためのライブラリ。
従来のフォームライブラリとは異なり、React Hook Formは、フォームのデータのバリデーションやエラー処理を簡単に行うことができ、より高速でパフォーマンスが高いことが特徴。

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

## react-hook-formのメリット

- パフォーマンスの向上
    - react-hook-formでは、フォームデータの状態を手動で更新する必要がないため、再レンダリングが最小限に抑えられます。これにより、フォームのパフォーマンスが向上します。

- 簡単なバリデーションの実装
    - react-hook-formでは、簡単なバリデーションルールを指定するだけで、フォームのバリデーションを実装できます。バリデーションエラーが発生した場合には、自動的にエラーメッセージが表示されます。

- フォームデータの管理が簡単
    - react-hook-formでは、フォームデータの状態を手動で管理する必要がないため、フォームの状態管理が簡単になります。また、フォームデータの状態は、Reactの状態管理ライブラリ（useStateなど）を使用するよりも効率的に管理できます。

- カスタムコンポーネントとの連携が簡単
    - react-hook-formは、カスタムコンポーネントとの連携が簡単です。カスタムコンポーネントを使用することで、フォームの見た目を自由に設定することができます。

- 柔軟なAPI
    - react-hook-formには、柔軟なAPIが用意されています。たとえば、フォームのバリデーションルールをカスタマイズしたり、フォームデータをJSON形式で出力することもできます。また、React Nativeで使用することもできます。

## React Hook Formを使用しない場合のサンプルコード

Reactの基本的なことを理解していればわかりやすいコードですが、handleSubmitのロジックが冗長になってしまいます。
また、入力値の分だけuseStateを用意する必要があります。

```jsx
import React, { useState } from "react";

function ContactForm() {
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [firstNameError, setFirstNameError] = useState("");
  const [lastNameError, setLastNameError] = useState("");

  const validateName = (name) => {
    const regex = /^[A-Za-z]+$/;
    return regex.test(name);
  };

  const handleSubmit = (e) => {
    e.preventDefault();

    if (!validateName(firstName)) {
      setFirstNameError("First name must contain only letters");
    } else {
      setFirstNameError("");
    }

    if (!validateName(lastName)) {
      setLastNameError("Last name must contain only letters");
    } else {
      setLastNameError("");
    }

    if (validateName(firstName) && validateName(lastName)) {
      console.log({ firstName, lastName });
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="firstName">First Name</label>
      <input
        type="text"
        name="firstName"
        id="firstName"
        value={firstName}
        onChange={(e) => setFirstName(e.target.value)}
      />
      {firstNameError && <span>{firstNameError}</span>}

      <label htmlFor="lastName">Last Name</label>
      <input
        type="text"
        name="lastName"
        id="lastName"
        value={lastName}
        onChange={(e) => setLastName(e.target.value)}
      />
      {lastNameError && <span>{lastNameError}</span>}

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

export default ContactForm;
```



## React Hook Formを使用した場合のサンプルコード

react-hook-formの知識こそは必要ですが、上記のコードと比べ、handleSubmitのロジックやuseStateを書かなくていい分見やすいコードになります

```jsx
import React from "react";
import { useForm } from "react-hook-form";

function ContactForm() {
  const { register, handleSubmit, errors } = useForm();
  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label htmlFor="firstName">First Name</label>
      <input
        type="text"
        name="firstName"
        id="firstName"
        ref={register({ required: true, maxLength: 20 })}
      />
      {errors.firstName && errors.firstName.type === "required" && (
        <span>This field is required</span>
      )}
      {errors.firstName && errors.firstName.type === "maxLength" && (
        <span>Max length exceeded</span>
      )}

      <label htmlFor="lastName">Last Name</label>
      <input
        type="text"
        name="lastName"
        id="lastName"
        ref={register({ required: true, maxLength: 20 })}
      />
      {errors.lastName && errors.lastName.type === "required" && (
        <span>This field is required</span>
      )}
      {errors.lastName && errors.lastName.type === "maxLength" && (
        <span>Max length exceeded</span>
      )}

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

export default ContactForm;
```