とことんDevOps | 日本仮想化技術のDevOps技術情報メディア

DevOpsに関連する技術情報を幅広く提供していきます。

日本仮想化技術がお届けする「とことんDevOps」では、DevOpsに関する技術情報や、日々のDevOps業務の中での検証結果、TipsなどDevOpsのお役立ち情報をお届けします。
主なテーマ: DevOps、CI/CD、コンテナ開発、IaCなど
各種SNSのフォローもよろしくお願いいたします。

ReactでReact hook formを使ってみよう

こんにちは。 アドベントカレンダー8日目です。 今年はフロントエンドまわりであれこれ開発することが多かったので、振り返りを兼ねてこれからフロントエンド開発を始める方向けに入門編としてお送りしています。 最終日の25日には何かアプリケーションができていることが目標です。

↓最初から読み始めたい方はこちらか↓

devops-blog.virtualtech.jp

おさらい

Visual Studio Codeを使ったReactの開発環境の構築(第1回)から始まり、CSSフレームワークの1つであるtailwindcssを使ったUI開発(第2回)やコンポーネント化(第3回)について話しています。

開発サイクルを効率的に回していくための、サポート的や役割のツールとして、フォーマッター(第4回)、Linter(第5回)、バージョン管理(第6)について学んできました。

第7回では、Reactに戻って状態管理について理解を深めていきました。

今回のはなし

前回に引き続きReactの話題です。今回は、フォーム回りで便利なカスタムフックの1つであるReact hook formについて学んでいきます。

カスタムフックとは

フック(hook)は、React 16.8で追加された機能です。useStateやuseEffectなどReactが標準で提供しているフックですが、カスタムフックというものがあります。カスタムフックを使用することで、独自のフックを作成できます。

今回は独自でカスタムフックを作成するわけではありませんが、詳しく知りたい方は公式サイトをご覧ください。

ja.react.dev

React hook formとは

React hook formは、Reactでフォームを作成するためのライブラリです。React hook formを使うと、フォームのバリデーションやエラーの表示などを簡単に実装できます。

react-hook-form.com

なぜReact hook formを使うのか

React hook formを使うと、フォームのバリデーションやエラーの表示などを簡単に実装できます。また、React hook formは、Reactのフックを使っているので、Reactの知識があればすぐに使い始めることができます。
1からフォームのバリデーションやエラーの表示を実装するのは大変なので、このようなライブラリを使うことで、開発効率を上げることができます。

使い方

早速使ってみましょう。
パッケージをインストールします。次のコマンドを実行してください。

npm install react-hook-form

パッケージのインストールが完了したら、フォームを作成してみます。まずは、HTML部分を作成します。

"use client";

export default function Home() {
  return (
    <div className="p-5 container mx-auto md">
      <div>
        <p className="text-2xl">参加受付</p>
      </div>
      <div>
        <form>
          <div>
            <label className="block mb-2 text-sm">名前</label>
            <input
              type="text"
              className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
              placeholder="山田 太郎"
            />
          </div>
          <div>
            <label>メールアドレス</label>
            <input
              type="email"
              className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
              placeholder="example@example.com"
            />
          </div>
          <div>
            <label>参加人数</label>
            <input
              type="number"
              className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
              placeholder="1"
            />
          </div>
          <div>
            <button
              type="submit"
              className="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-lg disabled:opacity-50"
            >
              送信
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

画面のUIが準備できました。次に、React hook formを使ってバリデーションを実装していきます。最初に後で使う型エイリアスとデフォルト値を定義します。

"use client";

+ type Inputs = {
+   name: string;
+   email: string;
+   count: number;
+ };

+ const defaultValues: Inputs = {
+   name: "",
+   email: "",
+   count: 1,
+ };

export default function Home() {
...

次にuseForm()を使ってフォームを作成します。先ほど宣言したInputsdefaultValuesを渡します。

const { register } = useForm<Inputs>({ defaultValues });

これからいくつかの関数を使いますが、まずはregisterを使って準備を進めていきます。registerは、フォームの各要素で使用する関数を提供しています。例えば、onChangeやref、nameなどです。これらの情報は個別で設定せずに、registerを使って一括で指定します。

名前

<input
  type="text"
  className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
  placeholder="山田 太郎"
+ {...register("name")}
/>

メールアドレス

<input
  type="email"
  className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
  placeholder="example@example.com"
+ {...register("email")}
/>

参加人数

<input
  type="number"
  className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
  placeholder="1"
+ {...register("count")}
/>

これでフォームの準備ができました。次に、送信ボタンを押したときに実行する関数を作成します。

handleSubmitを使って、フォームの送信時に実行する関数を作成します。handleSubmitは、フォームの送信時に実行する関数を引数に取ります。引数には、フォームの入力値が渡されます。

  const {
    register,
+   handleSubmit
  } = useForm<Inputs>({ defaultValues });

次に送信ボタンを押された際の処理を実装します。handleSubmitに、フォームの送信時に実行する関数を渡します。今回は、簡単に入力された内容をアラートに表示するような処理を実装します。

...
export default function Home() {
  const { register, handleSubmit } = useForm<Inputs>({ defaultValues });

+ const onSubmit = (data: Inputs) => {
+   const message = `こんにちは、${data.name}さん!\n受付しました。当日のお越しをお待ちしております。\nメールアドレス: ${data.email}\n参加人数: ${data.count}`;
+   alert(message);
+ };

  return (
...

作成したonSubmitを呼び出すために、formタグにonSubmitを設定します。

...
  return (
    <div className="p-5 container mx-auto md">
      <div>
        <p className="text-2xl">参加受付</p>
      </div>
      <div>
-       <form>
+       <form onSubmit={handleSubmit(onSubmit)}>
...

コードを変更が終わったら、ブラウザで確認してみましょう。フォームに入力して送信ボタンを押すと、アラートが表示されます。

ここまででも、かなり楽になったのですがもう少し改善していきます。まずは、バリデーションを実装していきます。
今回は全ての入力項目に対して、必須チェックを実装します。必須チェックは、requiredを使って実装します。

入力項目を必須化する場合には、{...register(...)}{ required: true }を追加します。

{...register("name", { required: true })}

名前以外の入力項目も同様に必須化します。

次にフォームの状態に応じたステータスを取得するための準備をします。今回は、isValidを使います。isValidは、入力項目に対してバリデーションが通っているかどうかを判定するためのステータスです。isValidは、formStateから取得します。

  const {
    register,
    handleSubmit,
+   formState: { isValid },
  } = useForm<Inputs>({ defaultValues });

次に、送信ボタンのdisabledisValidに設定します。

<button
  type="submit"
+ disabled={!isValid}
  className="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-lg"
>
  送信
</button>

改めて画面を確認してみましょう。フォームの入力が完了していない場合は、送信ボタンが押せないようになっていることが確認できます。

このように、React hook formを使うことで、フォームのバリデーションやエラーの表示を簡単に実装ができます。

コード全体

クリックして全体を表示

"use client";

import { useForm } from "react-hook-form";

type Inputs = {
  name: string;
  email: string;
  count: number;
};

const defaultValues: Inputs = {
  name: "",
  email: "",
  count: 1,
};

export default function Home() {
  const {
    register,
    handleSubmit,
    formState: { isValid },
  } = useForm<Inputs>({ defaultValues });

  const onSubmit = (data: Inputs) => {
    const message = `こんにちは、${data.name}さん!\n受付しました。当日のお越しをお待ちしております。\nメールアドレス: ${data.email}\n参加人数: ${data.count}`;
    alert(message);
  };

  return (
    <div className="p-5 container mx-auto md">
      <div>
        <p className="text-2xl">参加受付</p>
      </div>
      <div>
        <form onSubmit={handleSubmit(onSubmit)}>
          <div>
            <label className="block mb-2 text-sm">名前</label>
            <input
              type="text"
              className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
              placeholder="山田 太郎"
              {...register("name", { required: true })}
            />
          </div>
          <div>
            <label>メールアドレス</label>
            <input
              type="email"
              className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
              placeholder="example@example.com"
              {...register("email", { required: true })}
            />
          </div>
          <div>
            <label>参加人数</label>
            <input
              type="number"
              className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
              placeholder="1"
              {...register("count", { required: true })}
            />
          </div>
          <div>
            <button
              type="submit"
              disabled={!isValid}
              className="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-lg disabled:opacity-50"
            >
              送信
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

おわりに

今回は、React hook formを使ってフォームのバリデーションやエラーの表示を簡単に実装する方法を学びました。React hook formは、Reactのフックを使っているので、Reactの知識があればすぐに使い始めることができます。ぜひ、React hook formを使ってみてください。