![React Hook Formを使用したバリデート付きフォーム作成術](https://iwb.jp/wp-content/uploads/2024/06/react-hook-form-javascript-validate.png)
目次
React Hook Formとは
React Hook FormはReactアプリケーションでフォームを簡単に扱うためのライブラリです。
React Hook Formを使うには、まずReactが使える開発環境を作成して、react-hook-formをインストールします。
npm create vite@latest my-react-form -- --template react-swc-ts
フォームの見た目を良くするために、bulmaもインストールしておきます。
cd my-react-form
npm install
npm i -D react-hook-form bulma
App.cssにbulma.cssをimportします。
@import "bulma/css/bulma.css";
main.tsxの「import './index.css'」は使わないので削除します。
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
React Hook Form テキストの入力
App.tsxを以下のコードに変更します。
import './App.css'
import { useForm } from 'react-hook-form'
type FormData = {
name: string
}
export default function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormData>({ mode: 'onTouched' })
const onSubmit = handleSubmit((data) =>
alert(`名前:${data.name}`)
)
return (
<section className="section">
<div className="container is-max-desktop">
<form className="box" onSubmit={onSubmit}>
<div className="field">
<label className="label">名前</label>
<input
className="input"
type="text"
{...register("name", {
required: "テキストを入力してください",
minLength: {
value: 2,
message: "名前は2文字以上で入力してください",
},
maxLength: {
value: 10,
message: "名前は10文字以下で入力してください",
},
})}
/>
{errors.name && (
<p className="help is-danger">{errors.name.message}</p>
)}
</div>
<div className="field">
<button type="submit" className="button is-primary">
送信する
</button>
</div>
</form>
</div>
</section>
)
}
コード内の「mode: 'onTouched'」は最初はblurイベントでトリガーして、その後はchangeイベントでトリガーされます。
ユーザビリティ面を考慮した場合、フォームのバリデートは「mode: 'onTouched'」にしたほうが使いやすいです。
modeを設定しないと、submitボタンを押してからバリデートを開始する設定になってしまうので、modeは必ず設定してください。
React Hook Form 数値入力
数値の入力の場合は以下のようになります。
import './App.css'
import { useForm } from 'react-hook-form'
type FormData = {
age: number
}
export default function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormData>({ mode: 'onTouched' })
const onSubmit = handleSubmit((data) =>
alert(`年齢:${data.age}`)
)
return (
<section className="section">
<div className="container is-max-desktop">
<form className="box" onSubmit={onSubmit}>
<div className="field">
<label className="label">年齢</label>
<input
className="input"
type="number"
{...register("age", {
required: "年齢を入力してください",
min: {
value: 18,
message: "18歳以上で入力してください",
},
max: {
value: 120,
message: "120歳以下で入力してください",
},
valueAsNumber: true,
})}
/>
{errors.age && (
<p className="help is-danger">{errors.age.message}</p>
)}
</div>
<div className="field">
<button type="submit" className="button is-primary">
送信する
</button>
</div>
</form>
</div>
</section>
)
}
React Hook Form 正規表現チェック
入力部分に正規表現のバリデートを追加したい場合はpatternを使用します。
import './App.css'
import { useForm } from 'react-hook-form'
type FormData = {
email: string
}
export default function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormData>({ mode: 'onTouched' })
const onSubmit = handleSubmit((data) =>
alert(`メールアドレス:${data.email}`)
)
return (
<section className="section">
<div className="container is-max-desktop">
<form className="box" onSubmit={onSubmit}>
<div className="field">
<label className="label">メールアドレス</label>
<input
className="input"
type="email"
{...register("email", {
required: "メールアドレスを入力してください",
pattern: {
value: /.+@.+/,
message: "メールアドレスの入力形式が正しくないです",
},
})}
/>
{errors.email && (
<p className="help is-danger">{errors.email.message}</p>
)}
</div>
<div className="field">
<button type="submit" className="button is-primary">
送信する
</button>
</div>
</form>
</div>
</section>
)
}
Zodでスキーマバリデーション
React Hook Formはスキーマバリデーションに対応しているので、Zodを使用すればより簡単にバリデートの設定ができます。
設定するには、まずZodと@hookform/resolversをインストールします。
npm i -D zod @hookform/resolvers
インストールしたらApp.tsxを以下のZodを使用したコード貼り付けてください。
前述のemailのバリデートをZodを使用したコードに書き換えています。
import './App.css'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import { zodResolver } from '@hookform/resolvers/zod'
type FormData = {
email: string
}
const schema = z.object({
email: z
.string()
.trim()
.min(1, { message: 'メールアドレスを入力してください' })
.email({ message: 'メールアドレスの入力形式が正しくないです' })
})
export default function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormData>({
mode: 'onTouched',
resolver: zodResolver(schema),
})
const onSubmit = handleSubmit((data) =>
alert(`メールアドレス:${data.email}`)
)
return (
<section className="section">
<div className="container is-max-desktop">
<form className="box" onSubmit={onSubmit}>
<div className="field">
<label className="label">メールアドレス</label>
<input
className="input"
type="email"
{...register("email")}
/>
{errors.email && (
<p className="help is-danger">{errors.email.message}</p>
)}
</div>
<div className="field">
<button type="submit" className="button is-primary">
送信する
</button>
</div>
</form>
</div>
</section>
)
}
Zodの使い方は公式サイトを参照してください。
z.string()のようにメソッドをつなげる書き方なので、簡単に設定できます。
Zod使用前より使用後のほうがコードが「…register」部分に条件を書かなくて良いので、コードがだいぶスッキリして見やすくなります。
特に理由がなければ、React Hook Formを使用する際はZodを併用することをオススメします。