0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

React Hook Formというフォームを作ることに特化したライブラリの基礎を紹介します。

今の業務で使っているのですが、見様見真似でやっている状態なので備忘も兼ねてまとめていきます。

なお、本記事においては
React 18.2.0
TypeScript 5.2.2
Vite 5.2.0
を使用しています。

React Hook Formとは

概要

その名の通り、フォームを作ることに特化したライブラリです。

Performant, flexible and extensible forms with easy-to-use validation.

とあるように、パフォーマンス、柔軟性、拡張性に優れており、また簡単にバリデーションを実行できるのが特徴です。

どのようなものが作れるか

App.tsx
import { useForm, SubmitHandler } from "react-hook-form";

type Inputs = {
  example: string;
  exampleRequired: string;
};
const App = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<Inputs>();
  const onSubmit: SubmitHandler<Inputs> = (data) => console.log(data);
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input defaultValue="test" {...register("example")} />
      <input {...register("exampleRequired", { required: true })} />
      {errors.exampleRequired && <span>This field is required</span>}
      <input type="submit" />
    </form>
  );
};

export default App;

公式サイトから抜粋してきたコードです。
(コメントなど一部不要な記載を削除)

画面は以下のようになります。

この状態で送信ボタンを押すと

2つめの入力欄が必須である旨のメッセージが出ます。

値を入力するとメッセージは消えます。
この状態で送信ボタンを押すと

コンソールにフォームの入力値が出力されます。

それだけか、と思うかもしれませんが、実は結構すごいのです。

まずバリデーションの処理を書いていません。
{ required: true }みたいなそれらしきものは設定していますが、自身でフォームを作成する際にはしっかり書く必要があります。

また、フォームの入力値を管理するstateがありません。
送信後の値を取得する処理も書いていません。

この辺をまるっとやってくれているのがReactHookFormです。

では早速どのように書くのかを見ていきます。

ReactHookFormを試す

導入

まずはインストールする必要があるので(プロジェクトは作成済の想定)、以下のコマンドを入力します。

npm install react-hook-form

以下のように完了すればオッケーです。
image.png

入力フィールドの登録

この部分が一番大事な肝になります。
バリデーションとデータの送信に紐づけるための処理になります。

App.tsx
import { useForm, SubmitHandler } from "react-hook-form";

interface IFormInput {
  firstName: string;
  check: string;
}
const App = () => {
  const {
    register,
    handleSubmit,
  } = useForm<IFormInput>();
  const onSubmit: SubmitHandler<IFormInput> = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label>First Name</label>
        <input {...register("firstName")}/>
      </div>

      <div>
        <label>Check</label>
        <input type="checkbox" {...register("check")}/>
      </div>
      <input type="submit" />
    </form>
  );
};

export default App;

useFormの使用

ReactHookFormの基本はuseFormというカスタムフックを使うことです。
このフックを使うことにより、様々な機能を使うことができます。

このuseFormにはオブジェクトの形で引数を渡すことでいろいろ設定ができるのですが、今回は割愛して、戻り値であるregisterという関数に着目します。

register関数

inputタグ、またはselectタグに対して使用します。
引数としてname`属性に設定したい値を設定することで、バリデーションや値の送信時に紐づけることができます。

バリデーションの適用

先ほど使用したregister関数に、どんなときにエラーとしたいのかという情報を追加できます。

return文内のみ抜粋
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label>First Name</label>
        <input
          {...register("firstName", {
            required: true,
            minLength: { value: 3, message: "3文字以上で入力して下さい" },
          })}
        />
      </div>
      <div>
        <label>Check</label>
        <input
          type="checkbox"
          {...register("check", {
            required: { value: true, message: "check is required" },
          })}
        />
      </div>
      <input type="submit" />
    </form>
  );

バリデーションの設定

register関数に、オブジェクト形式で引数を渡します。
requierdの他、min, max, minLength, maxLengthなどhtmlタグに設定することができる属性は一通り設定が可能です。

また、単純にバリデーションに使用したい設定値を渡す代わりに
{value:設定値, message:'エラーメッセージ'}
の形式でオブジェクトを渡すことで、エラーメッセージのカスタマイズも可能になっています。

エラーハンドリング

上記でバリデーションの設定を行いましたが、今の状態でバリデーションエラーを起こしても何も起きません。

次にエラーハンドリングをする必要があります。

App.tsx
import { useForm, SubmitHandler } from "react-hook-form";

interface IFormInput {
  firstName: string;
  check: string;
}
const App = () => {
  const {
    register,
    formState: { errors },
    handleSubmit,
  } = useForm<IFormInput>();
  const onSubmit: SubmitHandler<IFormInput> = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label>First Name</label>
        <input
          {...register("firstName", {
            required: true,
            minLength: { value: 3, message: "3文字以上で入力して下さい" },
          })}
        />
        {errors.firstName?.type === "required" && "必須です"}
        {errors.firstName?.type === "minLength" && errors.firstName.message}
      </div>

      <div>
        <label>Check</label>
        <input
          type="checkbox"
          {...register("check", {
            required: { value: true, message: "check is required" },
          })}
        />
        {errors.check && errors.check.message}
      </div>
      <input type="submit" />
    </form>
  );
};

export default App;

errosの使用

エラーの情報を扱うにはuseFormフックが返すformStateerrorsを使用します。

errorsにはregister関数で登録したnameに紐づく形でエラーの情報が格納されます。
エラーがない場合には何も入ってきません。

errorsnameに紐づくtypeにはどのタイプのバリデーションエラーなのかが格納されます。
firstNameには必須チェック(required)と、最低文字数チェック(minLength)を設定しているので、それぞれのエラーについて出力するメッセージを指定しています。

必須チェックの場合はregister関数においてmessageを指定しなかったので、任意のメッセージを指定。
最低文字数チェックの場合には設定したmessageを取得しています。

このように、errorからバリデーションの結果を取得することによって、エラー時の挙動を決めることができます。

挙動確認

ではここまでで一通り設定ができたので動きを確認します。

初期状態です。

そのまま送信ボタンを押すと、それぞれ必須チェックに引っかかります。

値を設定すると、Checkのエラーは消えますが、FirstNameは文字数のエラーに変わります。

適切な文字数を入力して送信すると

コンソールにフォームの値が出力されました。送信成功です。
image.png

まとめ

ReactHookFormを使ってお手軽にフォームの作成、バリデーションを実施する方法を確認してきました。

自分であれこれ考えなくても、お作法に則ってパラメータを設定するだけであとはやってくれるので非常に楽です。

まだ上記で紹介した者は本当にさわりの部分だけなので、また機会を見つけていろいろな機能を紹介していきます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?