当サイトは、アフィリエイト広告を利用しています

ReactHookForm(V7)の使い方

作成日:2022月06月04日
更新日:2024年01月28日

React Hook Form(V7)を使ってサンプル実装して 基本的な使い方をまとめる。

React Hook Formとは?

reactでformを作る際にinputやバリデーションを簡単にできるライブラリ。
今回はv7で実装サンプル等を作る。

インストール

必要なパッケージをインストールする

yarn
# package本体
yarn add react-hook-form

サンプル実装

基本的な入力画面を実装をして動作を確認する。

サンプル画面の仕様

機能としては下記を行えるようにする。

  • 入力
  • バリデーションチェック
  • 送信(submit)※サンプルのためログ出力

全体ソース

App.js
/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react";
import { useForm } from "react-hook-form";
const SampleForm = () => {
// 使うメソッドを取得する
const { register, handleSubmit, reset, formState } = useForm();
// submit処理
const onSubmit = (data) => {
console.log(data);
reset();
};
return (
<form onSubmit={handleSubmit(onSubmit)} css={[container]}>
{/* input登録(name) */}
<input
placeholder="名前"
{...register("name", {
required: "名前は必須入力です",
maxLength: { value: 2, message: "入力が多すぎます" }
})}
/>
{/* エラーチェック結果 */}
{formState.errors.name && formState.errors.name.type === "required" && (
<span css={[error]}>{formState.errors.name.message}</span>
)}
{formState.errors.name && formState.errors.name.type === "maxLength" && (
<span css={[error]}>{formState.errors.name.message}</span>
)}
{/* input登録(mail) */}
<input
placeholder="メールアドレス"
{...register("email", {
required: "メールアドレスは必須入力です",
maxLength: 60,
pattern: {
value: /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,
message: "メールアドレスの形式が不正です"
}
})}
/>
{/* エラーチェック結果 */}
{formState.errors.email && formState.errors.email.type === "required" && (
<span css={[error]}>{formState.errors.email.message}</span>
)}
{formState.errors.email && formState.errors.email.type === "pattern" && (
<span css={[error]}>{formState.errors.email.message}</span>
)}
{/* submit */}
<button type="submit">送信</button>
</form>
);
};
export default SampleForm;
const container = () => [
css`
display: flex;
margin: 10%;
gap: 5px;
flex-direction: column;
justify-content: center;
align-items: flex-center;
/* height:80vh; */
`
];
const error = () => [
css`
color: red;
`
];

codesandboxで動作確認

上記ソースをcodesandboxでコーディングして動作確認する。

React Hook Form V7 Sample

サンプル実装の解説

useForm

まずはuseFormを呼び出してhookformの初期設定を行い使いたいメソッドを取得する。
基本的には下記を取得することになる。
※他にもいっぱいあるので詳しく知りたい場合は公式useForm参照

App.js
// 使うメソッドを取得する
const { register, handleSubmit, reset, formState } = useForm({
defaultValues: { name: "aaa", email: "test@test.com" }
});

useFormの引数(初期設定をする)

使うメソッド取得時のuseFormには引数としてオプションを渡すことができる。
渡さない場合は下記はデフォルト設定値が適用される。

Sample.js
useForm({
mode: 'onSubmit', //初回バリデーション
reValidateMode: 'onChange',//初回以降のバリデーションタイミング
defaultValues: {},//formの初期値
resolver: undefined,//??
context: undefined,//??
criteriaMode: "firstError",//all or firstError
shouldFocusError: true,//エラー位置にフォーカスするか
shouldUnregister: false,//アンマウント時に値の参照を保持するか trueで解除
shouldUseNativeValidation: false,//ブラウザの元々のバリデーションを有効にするか
delayError: undefined//エラーを遅らせる
})

??はちょっとわからないやつ。。。。

register

formに入力または選択要素を登録し、検証ルールも同時に設定できるメソッド 第一引数にname、第二引数に検証ルールを設定したオブジェクトを渡す。

App.js
//~
{/* input登録(name) */}
<input
placeholder="名前"
{...register("name", {
required: "名前は必須入力です",
maxLength: { value: 2, message: "入力が多すぎます" }
})}
/>
{/* エラーチェック結果 */}
{formState.errors.name && formState.errors.name.type === "required" && (
<span css={[error]}>{formState.errors.name.message}</span>
)}
{formState.errors.name && formState.errors.name.type === "maxLength" && (
<span css={[error]}>{formState.errors.name.message}</span>
)}
//~
  • input要素内でregisterメソッドを呼び出し、戻り値をスプレッド構文で展開して取得している。
  • 検証結果のエラー情報はformState.errorsに格納されるためあればエラー表示する

handleSubmit

フォームバリデーションに成功するとラップした関数にformのdataをオブジェクトの形で渡してくれる

App.js
// ~
// submit処理
const onSubmit = (data) => {
console.log(data);
reset();
};
return (
<form onSubmit={handleSubmit(onSubmit)} css={[container]}>
// ~

handleSubmitでラップした関数onSubmitにはdataとしてformのオブジェクトが渡される
実行結果は下記のようになる

log
{name: "aa", email: "test@test.com"}

formState

formの情報を保持するオブジェクト
詳しく知りたい場合は公式useForm参照

formStateのerrorsだけ分割代入して使っているパターンをよく見かける。

App.js
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm();

reset

初期化する関数

エラーハンドリングについて

React Hook Formの入力チェックでは 基本的にエラー情報はformStateに格納されるのでそれを利用する

ベーシックな方法

サンプル実装でも使った基本的なエラーハンドリング方法。 reacthookformでは下記のバリデーションが用意されている

  • required
  • maxLength
  • minLength
  • max
  • min
  • pattern
  • validate

...などなど詳しくはregisterを参照

App.js
//~
<form onSubmit={handleSubmit(onSubmit)} css={[container]}>
<input
{...register("name", {
required: "必須入力です",
maxLength: { value: 2, message: "入力が多すぎます" }
})}
/>
{/* エラーチェック結果 */}
{formState.errors.name && formState.errors.name.type === "required" && (
<span>{formState.errors.name.message}</span>
)}
{formState.errors.name && formState.errors.name.type === "maxLength" && (
<span>{formState.errors.name.message}</span>
)}
{/* submit */}
<button type="submit">Submit</button>
</form>
//~
  • registerの第二引数で検証ルールとエラーメッセージをオブジェクトで渡して登録
  • formStateの中にエラーがあった場合は出力する

ErrorMessageコンポーネントを使う

@hookform/error-messageのパッケージをインストールして
ErrorMessageコンポーネントを使うこともできる

インストール

bash
yarn add @hookform/error-message

ErrorMessageコンポーネントには

  • nama → フィールド名
  • errors → 検証情報が格納されているオブジェクト(基本はformStateかその配下のオブジェクト)
  • render → 複数メッセージを出す時ためのレンダリングプロップ

を設定する

単一エラーを出す場合

App.js
<form onSubmit={handleSubmit(onSubmit)} css={[container]}>
{/* input登録(name) */}
<input
{...register("name", {
required: "必須入力です",
maxLength: { value: 2, message: "入力が多すぎます" },
max: {
value: 3,
message: "値が大きすぎます" // JS only: <p>error message</p> TS only support string
}
})}
/>
{/* エラーチェック結果 */}
<ErrorMessage errors={formState.errors} name="name" />
{/* submit */}
<button type="submit">Submit</button>
</form>

複数検証ルール

複数検証を行い、エラーメッセージを複数出力する必要がある場合は
レンダリングプロップを使う。

複数エラーを出す場合

App.js
<form onSubmit={handleSubmit(onSubmit)} css={[container]}>
{/* input登録(name) */}
<input
{...register("name", {
required: "必須入力です",
maxLength: { value: 2, message: "入力が多すぎます" },
max: {
value: 3,
message: "値が大きすぎます"
}
})}
/>
<ErrorMessage
errors={formState.errors}
name="name"
render={({ messages }) => {
console.log(messages);
return Object.entries(messages).map(([type, message]) => (
<div key={type}>{message}</div>
));
}}
/>
{/* submit */}
<button type="submit">Submit</button>
</form>
  • useForm作成時にcriteriaModeをallにしてする

詳しくはエラーメッセージ参照

複数検証ルールを設定する必要がある場合はregisterに渡すオブジェクトを外で定義した方が
コードがすっきりする

App.jsx
// 使うメソッドを取得する
const { register, handleSubmit, reset, formState } = useForm({
defaultValues: { name: "aaa", email: "test@test.com" },
criteriaMode: "all"
});
// 検証ルールオブジェクトを定義
const checkRule = {
required: "必須入力です",
maxLength: { value: 2, message: "入力が多すぎます" },
max: {
value: 3,
message: "値が大きすぎます"
}
};
return (
<form onSubmit={handleSubmit(onSubmit)} css={[container]}>
{/* input登録(name) */}
<input
{...register("name", checkRule)} //検証ルールオブジェクトを渡す
/>
<ErrorMessage
errors={formState.errors}
name="name"
render={({ messages }) => {
console.log(messages);
return Object.entries(messages).map(([type, message]) => (
<div key={type}>{message}</div>
));
}}
/>
{/* submit */}
<button type="submit">Submit</button>
</form>
);
  • 検証ルールオブジェクトを定義する

codesandboxで動作確認

ErrorMessageコンポーネントを使って複数検証ルールを外部で定義し、
複数エラーメッセージを出力するサンプル。

React Hook Form V7 @hookform/error-message

カスタムバリデーション

registerに渡す検証ルールオブジェクトのvalidateで独自のバリデーションを
設定できる

複数ルールを設定すう場合

validateの中でルール名と関数のセットを持ったオブジェクトを設定する

App.js
<input
{...register("test1", {
validate: {
positive: (v) => parseInt(v) > 0 || "should be greater than 0",
lessThanTen: (v) => parseInt(v) < 10 || "should be lower than 10",
}
})}
/>

単一ルールを設定する場合

単一ルールを設定する場合はオブジェクトの形にする必要はない

App.js
<input
{...register("test1", {
validate: (v) => parseInt(v) > 0 || "should be greater than 0"
})}
/>

詳しくはregister参照

React Hook Form(V7)でasync awaitを使う

handleSubmitメソッドは非同期で使うこともできる

App.js
/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react";
import { useForm } from "react-hook-form";
import React from "react";
import { ErrorMessage } from "@hookform/error-message";
import axios from "axios";
const SampleForm = () => {
// submit処理(async)
const onSubmit = async data => {
const result = await axios.request({
method: "GET",
url: "https://jsonplaceholder.typicode.com/todos/1",
})
.catch((error)=>error.message)
alert(JSON.stringify(result.data,null,2));
};
// 使うメソッドを取得する
const { register, handleSubmit, reset, formState } = useForm({
defaultValues: { test1: "aaa"},
criteriaMode: "all"
});
// 検証ルールオブジェクトを定義
const checkRule = {
required: "必須入力です",
maxLength: { value: 2, message: "入力が多すぎます" },
max: {
value: 10,
message: "値が大きすぎます"
},
validate: (v) => parseInt(v) > 0 || "0以上で入力してください"
};
return (
<form onSubmit={handleSubmit(onSubmit)} css={[container]}>
<input {...register("test1", checkRule)} />
<ErrorMessage
errors={formState.errors}
name="test1"
render={({ messages }) => {
console.log(messages);
return Object.entries(messages).map(([type, message]) => (
<div key={type}>{message}</div>
));
}}
/>
{/* submit */}
<button type="submit">Submit</button>
</form>
);
};
export default SampleForm;
const container = () => [
css`
display: flex;
margin: 10%;
flex-direction: column;
justify-content: center;
align-items: flex-center;
/* height:80vh; */
`
];

詳しくはhandleSubmit参照

codesandboxで動作確認

React Hook Form V7 async

まとめ

実装の流れとしては下記のようになる。

  • useForm({})に初期設定をオブジェクトで渡して、設定をすると同時に使うメソッドを取得する。
  • registerメソッドでinputフィールドの登録と検証ルールを設定する。
  • エラーハンドリング処理を書く
  • バリデーション成功時の処理を書く。

reactでform(バリデーションあり)をライブラリなしで作ろうと思った場合、
なかなかに手間なので、このライブラリはかなり使えそうです。

参考

新着記事

タグ別一覧
top