0
2

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】React Hook Formの基本 - バリデーション機能付きフォームを簡単に実装する

Posted at

はじめに

React Hook Formとは

React Hook Formは、Reactでフォームを簡単に実装できるライブラリです。フォームの状態管理、バリデーション、エラー表示などを最小限のコードで実現できます。

従来のフォーム実装との違い

通常のReactでフォームを作成する場合、各入力フィールドに対してstateを定義し、onChange関数を実装する必要があります。しかし、React Hook Formを使用すると、これらの処理をライブラリが自動的に管理してくれるため、コード量を大幅に削減できます。

従来の実装では再レンダリングが頻繁に発生しますが、React Hook Formは非制御コンポーネントの仕組みを活用することで、パフォーマンスの向上も実現しています。

React Hook Formの基本的な使い方

インストール方法

npmまたはyarnを使用してインストールします。

npm install react-hook-form

最小構成のサンプルコード

以下は、商品名と数量を入力するシンプルなフォームの実装例です。

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

function RHFForm({ addItem }) {
  const {
    register,
    handleSubmit,
    formState: { errors },
    reset,
  } = useForm({
    defaultValues: {
      product: '',
      quantity: 0,
    },
  });

  const onSubmit = (data) => {
    console.log(data);
    addItem(data);
    reset();
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label htmlFor="product">商品名</label>
        <input
          id="product"
          type="text"
          {...register('product', { required: '商品名は空にできません' })}
        />
        {errors.product && errors.product.message}
      </div>
      <div>
        <label htmlFor="quantity">数量</label>
        <input
          id="quantity"
          {...register('quantity', {
            required: '数量を入力してください',
            valueAsNumber: true,
            min: { value: 1, message: '1以上を入力してください' },
          })}
        />
        {errors.quantity && errors.quantity.message}
      </div>

      <input type="submit" />
    </form>
  );
}

export default RHFForm;

useFormフックで取得できる主な機能

useFormフックは、フォーム管理に必要な機能をまとめて提供します。分割代入で必要なものだけを取り出して使用します。

register(入力フィールドの登録)

入力フィールドをReact Hook Formに登録するための関数です。この関数を使用することで、各フィールドの値を自動的に管理し、バリデーションルールを設定できます。

handleSubmit(送信処理のラップ)

フォーム送信時のハンドラーをラップする関数です。送信前に自動的にバリデーションを実行し、エラーがなければ指定したコールバック関数を呼び出します。

formState(フォームの状態管理)

フォームの状態を含むオブジェクトです。errorsプロパティを使用することで、バリデーションエラー情報にアクセスできます。

reset(フォームのリセット)

フォームの値を初期値にリセットする関数です。送信後にフォームをクリアする場合などに使用します。

defaultValues(初期値の設定)

useFormのオプションとして渡すことで、フォームの初期値を設定できます。この値は、reset()を呼び出したときにフォームが戻る値にもなります。

useForm({
  defaultValues: {
    product: '',
    quantity: 0,
  },
});

registerによる入力フィールドの管理

registerの基本的な使い方

register関数は、第1引数にフィールド名、第2引数にバリデーションルールを受け取ります。

register('product', { required: '商品名は空にできません' })

この関数は、以下のようなオブジェクトを返します。

{
  name: 'product',
  onChange: [関数],
  onBlur: [関数],
  ref: [関数]
}

スプレッド構文での展開

registerが返すオブジェクトをスプレッド構文で展開することで、必要なpropsをinput要素に一括で渡せます。

<input {...register('product', { required: '商品名は空にできません' })} />

これは以下のコードと同じ意味になります。

<input
  name="product"
  onChange={onChangeFunction}
  onBlur={onBlurFunction}
  ref={refFunction}
/>

バリデーションルールの設定

registerの第2引数にオブジェクト形式でバリデーションルールを指定します。複数のルールを組み合わせることも可能です。

register('quantity', {
  required: '数量を入力してください',
  valueAsNumber: true,
  min: { value: 1, message: '1以上を入力してください' },
})

バリデーションの実装

React Hook Formは、様々なバリデーションルールを簡単に設定できます。

必須入力チェック(required)

最も基本的なバリデーションです。フィールドが空の場合にエラーを表示します。

register('product', { required: '商品名は空にできません' })

真偽値だけを指定することもできますが、エラーメッセージを文字列で指定するのが一般的です。

数値変換(valueAsNumber)

input要素の値は通常文字列として扱われますが、valueAsNumber: trueを設定することで自動的に数値に変換されます。

register('quantity', {
  valueAsNumber: true,
})

これにより、送信されるデータのquantityプロパティが文字列の"5"ではなく、数値の5になります。

最小値チェック(min)

数値フィールドに対して最小値を設定できます。

register('quantity', {
  min: { value: 1, message: '1以上を入力してください' },
})

その他のバリデーションルール

React Hook Formは、他にも以下のようなバリデーションルールを提供しています。

  • max: 最大値のチェック
  • minLength: 最小文字数のチェック
  • maxLength: 最大文字数のチェック
  • pattern: 正規表現によるパターンマッチング
  • validate: カスタムバリデーション関数
register('email', {
  required: 'メールアドレスは必須です',
  pattern: {
    value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
    message: '有効なメールアドレスを入力してください',
  },
})

エラーメッセージの表示

errorsオブジェクトの使い方

formStateから取得できるerrorsオブジェクトには、各フィールドのバリデーションエラー情報が格納されています。エラーが発生していないフィールドはundefinedになります。

const { formState: { errors } } = useForm();

各フィールドのエラーにアクセスするには、フィールド名をキーとして使用します。

errors.product  // 商品名フィールドのエラー
errors.quantity // 数量フィールドのエラー

条件付きレンダリング

エラーメッセージは、エラーが存在する場合のみ表示するのが一般的です。論理AND演算子を使用した条件付きレンダリングで実装します。

{errors.product && errors.product.message}

これは以下のように動作します。

  • errors.productundefined(エラーなし)の場合、何も表示されない
  • errors.productが存在する(エラーあり)の場合、errors.product.messageの内容が表示される

より明示的に書く場合は、三項演算子を使用することもできます。

{errors.product ? <span>{errors.product.message}</span> : null}

フォーム送信処理の流れ

フォームの送信処理は、複数のステップを経て実行されます。Mermaid図で全体の流れを確認しましょう。

handleSubmitの役割

handleSubmitは、フォーム送信処理のゲートキーパーとして機能します。

<form onSubmit={handleSubmit(onSubmit)}>

この関数は以下の処理を自動的に実行します。

  1. フォームのデフォルト動作(ページリロード)を防ぐ
  2. 全フィールドのバリデーションを実行
  3. バリデーションが成功した場合のみ、引数で渡された関数を呼び出す
  4. バリデーションが失敗した場合、errorsオブジェクトを更新

onSubmit関数の実装

onSubmit関数は、バリデーションが成功した場合のみ実行されます。引数のdataには、全フィールドの値がオブジェクトとして渡されます。

const onSubmit = (data) => {
  console.log(data);  // { product: '商品名', quantity: 5 }
  addItem(data);
  reset();
};

dataオブジェクトの構造は、registerで登録したフィールド名がキーとなります。

親コンポーネントへのデータ受け渡し

addItem(data)を呼び出すことで、親コンポーネントにデータを渡しています。これはJavaScriptの関数参照の仕組みによるものです。

親コンポーネントから渡されたaddItem関数は、propsを通じて子コンポーネントに「関数そのもの」が渡されています。そのため、子コンポーネントでaddItem(data)を実行すると、実際には親コンポーネントで定義された関数が実行され、親のstateを更新できます。

まとめ

React Hook Formを使用することで、以下のメリットが得られます。

コード量の削減: 従来の実装と比較して、状態管理やイベントハンドラのコードを大幅に削減できます。

宣言的なバリデーション: バリデーションルールをオブジェクトとして宣言的に記述できるため、可読性が向上します。

パフォーマンスの向上: 非制御コンポーネントの仕組みを活用することで、不要な再レンダリングを抑制できます。

型安全性: TypeScriptと組み合わせることで、フォームデータの型安全性を確保できます。

React Hook Formは、シンプルなフォームから複雑なフォームまで幅広く対応できる強力なライブラリです。基本的な使い方を理解することで、効率的にフォームを実装できるようになります。

0
2
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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?