当サイトは、アフィリエイト広告を利用しています
React Hook Form(V7)を使ってサンプル実装して 基本的な使い方をまとめる。
reactでformを作る際にinputやバリデーションを簡単にできるライブラリ。
今回はv7で実装サンプル等を作る。
必要なパッケージをインストールする
# package本体yarn add react-hook-form
基本的な入力画面を実装をして動作を確認する。
機能としては下記を行えるようにする。
/** @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) */}<inputplaceholder="名前"{...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) */}<inputplaceholder="メールアドレス"{...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でコーディングして動作確認する。
まずはuseFormを呼び出してhookformの初期設定を行い使いたいメソッドを取得する。
基本的には下記を取得することになる。
※他にもいっぱいあるので詳しく知りたい場合は公式useForm参照
// 使うメソッドを取得するconst { register, handleSubmit, reset, formState } = useForm({defaultValues: { name: "aaa", email: "test@test.com" }});
使うメソッド取得時のuseFormには引数としてオプションを渡すことができる。
渡さない場合は下記はデフォルト設定値が適用される。
useForm({mode: 'onSubmit', //初回バリデーションreValidateMode: 'onChange',//初回以降のバリデーションタイミングdefaultValues: {},//formの初期値resolver: undefined,//??context: undefined,//??criteriaMode: "firstError",//all or firstErrorshouldFocusError: true,//エラー位置にフォーカスするかshouldUnregister: false,//アンマウント時に値の参照を保持するか trueで解除shouldUseNativeValidation: false,//ブラウザの元々のバリデーションを有効にするかdelayError: undefined//エラーを遅らせる})
??はちょっとわからないやつ。。。。
formに入力または選択要素を登録し、検証ルールも同時に設定できるメソッド 第一引数にname、第二引数に検証ルールを設定したオブジェクトを渡す。
//~{/* input登録(name) */}<inputplaceholder="名前"{...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>)}//~
フォームバリデーションに成功するとラップした関数にformのdataをオブジェクトの形で渡してくれる
// ~// submit処理const onSubmit = (data) => {console.log(data);reset();};return (<form onSubmit={handleSubmit(onSubmit)} css={[container]}>// ~
handleSubmitでラップした関数onSubmitにはdataとしてformのオブジェクトが渡される
実行結果は下記のようになる
{name: "aa", email: "test@test.com"}
formの情報を保持するオブジェクト
詳しく知りたい場合は公式useForm参照
formStateのerrorsだけ分割代入して使っているパターンをよく見かける。
const {register,handleSubmit,reset,formState: { errors },} = useForm();
初期化する関数
React Hook Formの入力チェックでは 基本的にエラー情報はformStateに格納されるのでそれを利用する
サンプル実装でも使った基本的なエラーハンドリング方法。 reacthookformでは下記のバリデーションが用意されている
...などなど詳しくはregisterを参照
//~<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>//~
@hookform/error-messageのパッケージをインストールして
ErrorMessageコンポーネントを使うこともできる
yarn add @hookform/error-message
ErrorMessageコンポーネントには
を設定する
<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>
複数検証を行い、エラーメッセージを複数出力する必要がある場合は
レンダリングプロップを使う。
<form onSubmit={handleSubmit(onSubmit)} css={[container]}>{/* input登録(name) */}<input{...register("name", {required: "必須入力です",maxLength: { value: 2, message: "入力が多すぎます" },max: {value: 3,message: "値が大きすぎます"}})}/><ErrorMessageerrors={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>
詳しくはエラーメッセージ参照
複数検証ルールを設定する必要がある場合はregisterに渡すオブジェクトを外で定義した方が
コードがすっきりする
// 使うメソッドを取得する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)} //検証ルールオブジェクトを渡す/><ErrorMessageerrors={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>);
ErrorMessageコンポーネントを使って複数検証ルールを外部で定義し、
複数エラーメッセージを出力するサンプル。
registerに渡す検証ルールオブジェクトのvalidateで独自のバリデーションを
設定できる
validateの中でルール名と関数のセットを持ったオブジェクトを設定する
<input{...register("test1", {validate: {positive: (v) => parseInt(v) > 0 || "should be greater than 0",lessThanTen: (v) => parseInt(v) < 10 || "should be lower than 10",}})}/>
単一ルールを設定する場合はオブジェクトの形にする必要はない
<input{...register("test1", {validate: (v) => parseInt(v) > 0 || "should be greater than 0"})}/>
詳しくはregister参照
handleSubmitメソッドは非同期で使うこともできる
/** @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)} /><ErrorMessageerrors={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参照
実装の流れとしては下記のようになる。
reactでform(バリデーションあり)をライブラリなしで作ろうと思った場合、
なかなかに手間なので、このライブラリはかなり使えそうです。