ReactHookFormの使い方・Zod連携や配列操作【プロが解説】
この記事のポイント
React Hook Formは、非制御コンポーネントにより再レンダリングを防いで高速動作とコード削減を実現し、Zodによるスキーマバリデーションや外部UIとの連携を通じて、複雑な動的フォームを最小限の記述で構築できるフォーム管理ライブラリです。
React Hook Formの基本的な使い方をマスターして、再レンダリングによるパフォーマンス低下やコードの複雑さを解消し、開発効率と保守性を劇的に高めたいと考えていませんか。
こうした疑問に答えます。
本記事の内容
- React-hook-formのインストールから基本実装までの流れ
- Controllerや配列を扱うuseFieldArrayなどの便利なAPI活用術
- Zodと連携したバリデーションやsetValue、watchの具体的な使い方
React Hook Formを活用すれば、最小限の記述でパフォーマンスに優れた高品質なフォームを構築できます。
モダンなフロントエンド開発のベストプラクティスを学び、現場で通用する実践的なスキルを身につけましょう。それでは詳しく解説します。
React Hook Formの主な特徴
React Hook Formは、Reactとは何かを踏まえた上で導入する、モダンなフォーム実装を効率化させるデファクトスタンダードなライブラリです。従来のuseStateを用いた制御コンポーネントによる管理とは異なり、非制御コンポーネントをベースに設計されています。 開発者は煩雑な状態管理から解放され、パフォーマンスの高いインターフェースを最小限のコードで実現可能です。React-hook-formの使い方は非常にシンプルで、導入により開発効率が劇的に向上します。
コードをシンプルに書ける
React Hook Formを採用する最大のメリットは、フォームの実装に必要なボイラープレートコードを大幅に削減できる点です。 従来のuseStateを利用する方法では、入力項目ごとにstateを定義し、onChangeイベントハンドラーを作成する必要がありました。
React-hook-formのインストール後は、useFormフックから提供されるregister関数をinput要素に適用するだけです。これにより、値の管理とReact-hook form validationを簡単に紐付けられます。
| 項目 | 従来のuseState | React Hook Form |
|---|---|---|
| 状態管理 | 項目ごとにuseStateが必要 | useForm一つで一括管理 |
| イベント制御 | onChange等のハンドラー定義が必須 | register関数だけで完結 |
| TypeScript連携 | 手動で型定義が必要 | ジェネリクスによる高い型安全性 |
register関数を活用することで、宣言的で可読性の高いコードを記述できます。
再レンダリングを最適化できる
React Hook Formは、大規模なフォームであっても非常に高いパフォーマンスを発揮します。 これは非制御コンポーネント設計を採用しており、入力値をReactのstateではなくref経由で管理しているためです。
制御コンポーネントでは1文字入力するたびに全体が再レンダリングされますが、このライブラリは必要なタイミング以外での再描画を抑制します。特定の項目の値だけを監視したい場合は、React-hook form watchを活用することで、柔軟な制御が可能です。
- 制御コンポーネント:入力のたびに親コンポーネントが再描画され、項目数が多いと動作が重くなる原因になる。
- React Hook Form:入力時には再描画が発生せず、サブミット時やエラー時など必要なときのみレンダリングされる。
この最適化により、ユーザー体験を損なうことなく、複雑なユーザーインターフェースを構築できます。
外部UIライブラリと簡単に連携できる
React Hook Formは、MUIやshadcn/uiといった外部UIライブラリともスムーズに連携できます。 React-hook form Controllerというコンポーネントを使用すれば、refを直接扱えない外部コンポーネントも管理下に置くことが可能です。
また、プログラムから値を操作したい場合はReact-hook-form setValueを利用することで、動的な値の変更も容易に行えます。
- Controllerコンポーネント:外部ライブラリとの架け橋となり、値の受け渡しを簡略化する。
- 高い柔軟性:Radix UIなどのヘッドレスUIライブラリとも自然な形で接続できる。
- 一貫したインターフェース:どのUIライブラリを使用していても、フォームのロジックは一つに集約される。
さらに、React-Hook Form配列(useFieldArray)を利用すれば、動的に増減する入力項目の管理も簡単です。
スキーマベースでバリデーションできる
バリデーションロジックをコンポーネントから切り離し、宣言的に記述できる点も大きな特徴です。 React Hook Formは、React-Hook Form zodといったスキーマバリデーションライブラリと簡単に統合できます。
Zodでルールを定義し、それを反映させるだけで、複雑なチェックも自動的に適用されます。
- バリデーションルールの共通化:フロントエンドとバックエンドで同じスキーマを共有しやすくなる。
- エラーハンドリングの簡素化:formState.errorsを参照するだけで適切なメッセージを表示できる。
- 型補完の強化:Zodのスキーマから型を抽出することで、フォーム全体の型安全性を確保できる。
特に最新のプロジェクトでは定番の組み合わせであり、保守性の高いコードを書くために欠かせない機能です。
React Hook Formの基本的な実装手順
React Hook Formの使い方は非常にシンプルで、コードの簡素化に役立ちます。useFormフックを中心とした直感的なAPIにより、以下のような恩恵が得られます。
- パフォーマンス向上:非制御コンポーネントで無駄な再レンダリングを回避。
- 記述の簡略化:バリデーション論理を宣言的に書けるため、コード量が減少。
- 型安全:TypeScriptと親和性が高く、標準で型サポートを提供。
①:パッケージをインストールする
まずはプロジェクトにReact Hook Formをインストールしましょう。このライブラリは軽量で依存関係が少なく、スムーズに導入できます。
React-hook-form インストールの際は、型定義ファイルが同梱されているため追加のパッケージは不要です。利用しているパッケージマネージャーに合わせて、以下のコマンドを実行してください。
- npmの場合:npm install react-hook-form
- yarnの場合:yarn add react-hook-form
- pnpmの場合:pnpm add react-hook-form
②:useFormを呼び出す
次に、フォーム全体の状態を管理するためにuseFormフックを呼び出します。useFormはReact Hooks として提供されるカスタムフックで、バリデーションルールやデフォルト値の設定など、フォームに必要な全機能を提供します。
React-Hook Form zodなどの外部ライブラリと連携する場合も、このuseFormで設定を行います。TypeScriptではジェネリクスを活用して、入力項目への型補完を有効にしましょう。
import { useForm } from 'react-hook-form';
type Inputs = {
email: string;
username: string;
};
const { register, handleSubmit, formState: { errors } } = useForm<Inputs>();
③:registerで入力要素を登録する
各入力フィールドを管理下に置くため、registerメソッドを活用します。このメソッドをinput要素に展開するだけで、値の監視とReact-hook form validationが有効になります。
React Hook Formは非制御コンポーネントがベースのため、手動のonChange設定は不要です。主なバリデーション設定の内容を以下の表に示します。
| プロパティ名 | 内容 | 設定例 |
|---|---|---|
| required | 必須入力の設定 | { required: "必須項目" } |
| pattern | 正規表現チェック | { pattern: /^\S+@\S+$/i } |
| minLength | 最小文字数の制限 | { minLength: 8 } |
| validate | カスタムバリデーション | (v) => v === "admin" |
④:handleSubmitで送信処理を設定する
フォームの送信処理にはhandleSubmitメソッドを使いましょう。これを利用すると、送信時にバリデーションを自動で実行してくれます。
全ての検証を通過したときのみ指定した関数が呼ばれるため、データの整合性を個別にチェックする必要はありません。MUIなどの外部ライブラリを使う際は、React-hook form Controllerを併用して制御コンポーネントを扱うのが一般的です。
- 送信時に実行するonSubmit関数を定義する
- formタグのonSubmitにhandleSubmit(onSubmit)を渡す
⑤:エラーメッセージの表示を制御する
最後に、formState内のerrorsオブジェクトを使ってエラーメッセージを表示します。ここには現在のエラー情報が格納されており、ユーザーへのフィードバックを容易にします。
React-hook form watchを使えばリアルタイムな入力監視も可能ですが、基本はerrorsの有無で条件分岐させます。複雑な動的フォームを扱うReact-Hook Form 配列の実装でも、このエラー制御は重要です。
{errors.email && <span>この項目は入力必須です</span>}
保守性を高めるには、React-hook-form setValueによる値の動的操作や、スキーマバリデーションの活用が効果的です。
React Hook Formの便利なAPI
実務で頻繁に利用される主要なAPIについて、それぞれの役割と具体的な活用法を解説します。
React-hook form watchを使った入力値の監視
React-hook form watchは、フォームの入力項目をリアルタイムで監視するために使用します。特定の入力内容に応じて表示を切り替えたり、条件付きのReact-hook form validationを実行したりすることが可能になります。
watchを利用する理由は、ユーザーの操作に迅速に反応する動的なUIを構築するためです。標準のuseStateとの比較 でいうと、入力値の変化を都度setStateで保持しなくても、watchが内部で参照を持って必要なタイミングで通知してくれます。「パスワード」と「確認用」の値を比較して一致を確認する場合などに役立ちます。
以下にwatchの基本動作と、よく比較されるgetValuesの違いをまとめました。
| API名 | 主な特徴 | 再レンダリング | 使用場面 |
|---|---|---|---|
| watch | 入力値を監視し、変更のたびにコンポーネントを更新する | あり | リアルタイムな表示反映が必要な場合 |
| getValues | 呼び出し時点での現在値を取得する | なし | 送信時や特定のボタンクリック時のみ値が必要な場合 |
watchを使用する際は、特定のフィールドのみを監視して再レンダリングを最適化しましょう。
- フォーム全体を監視:watch()
- 特定の一つの値を監視:watch("firstName")
- 複数の値を監視:watch(["firstName", "lastName"])
React-hook-form setValueを使った値の更新
React-hook-form setValueは、プログラムによってフォームの値を手動で変更するための関数です。外部データの読み込み後や別のコンポーネントからの指示で値を上書きしたい場合に使用します。
このAPIは、非制御コンポーネントをベースにするReact Hook Formにおいて命令的に値を操作する窓口となります。APIから取得した郵便番号データを各フィールドに自動反映させるケースなどで非常に有効です。
setValueの代表的なオプションは次の3つです。
| オプション | trueにした場合の挙動 |
|---|---|
| shouldValidate | 値の変更と同時にバリデーションが実行される |
| shouldDirty | フォームが変更済み状態としてマークされる |
| shouldTouch | 対象フィールドが一度触れられた状態になる |
setValueを活用することで、手動入力以外のデータフローも柔軟に制御できます。
React-hook form Controllerを使った外部UIとの連携
React-hook form Controllerは、MUI(Material-UI)などの外部ライブラリとReact Hook Formを統合するReactコンポーネント設計 の要となる仕組みです。
多くの外部ライブラリは内部で独自の状態を持つため、標準のregisterだけでは正しく値を追跡できません。Controllerを介することで、refを直接保持できないUIコンポーネントともスムーズに値を同期できます。
具体的には、MUIのTextFieldにfieldオブジェクトをスプレッドして渡すだけで、通常のinput要素と同じようにバリデーションやエラー表示を管理できます。モダンなデザインシステムを採用するプロジェクトでは、Controllerの使い方が非常に重要になります。
React-Hook Form 配列の操作
React-Hook Form 配列を扱うには、useFieldArrayというカスタムフックを利用します。TODOリストや職歴フォームなど、動的な項目の追加や削除を行う際に非常に便利です。
この機能のメリットは、配列操作に伴う複雑な状態管理をライブラリ側ですべて引き受けてくれる点にあります。インデックスの管理も提供されるメソッドを呼び出すだけで完結します。
useFieldArrayで提供される主なメソッドとその機能は以下の通りです。
- append:配列の最後に新しい項目を追加
- prepend:配列の先頭に新しい項目を追加
- remove:指定したインデックスの項目を削除
- move:項目を配列内で移動
- insert:指定した位置に項目を挿入
React-Hook Form zodなどのスキーマ定義と組み合わせれば、配列全体の件数制限も容易に定義できます。複雑なフォーム構造でも、useFieldArrayを使えば保守性の高いコードを実現できるでしょう。
React Hook Formにスキーマバリデーションを導入する手順
React Hook FormとZodの連携は、モダンなフロントエンド開発における標準的な手法です。バリデーションロジックをフォーム本体から切り離せるため、コードが非常にスッキリします。
① Zodをインストールする
まずはZod本体と、React Hook Formを接続するための専用ライブラリをインストールします。React TypeScriptとZodで型安全に 連携するには、公式の@hookform/resolversが必要です。
このライブラリを介して、Zodで定義した制約をReact Hook Formの動作に反映させます。各パッケージの具体的な役割は以下の通り。
| パッケージ名 | 役割 |
|---|---|
| zod | バリデーションスキーマの定義と型推論 |
| @hookform/resolvers | React Hook FormとZodを橋渡しする |
以下のコマンドをターミナルで実行してください。React-hook-formインストールの際に併せて導入しましょう。
- npm install zod @hookform/resolvers
- yarn add zod @hookform/resolvers
② バリデーションスキーマを定義する
次に、フォームの各項目に対するバリデーションルールを定義します。Zodを使う最大の利点は、定義したスキーマからTypeScriptの型を自動抽出できることです。
これにより入力値へ常に最新の型定義が適用され、開発時の安全性が保証されます。作業の流れは以下の通りです。
- z.objectを用いて、フォームの形状を定義する
- 各フィールドに文字列や必須チェック、メール形式などの制約を記述する
- z.inferを使用して、スキーマからTypeScriptの型を抽出する
メールアドレスとパスワードの構成なら、z.string().email()のように直感的なメソッドで定義可能です。React-hook form validationの設定が非常に楽になります。
③ リゾルバーでフォームに接続する
定義したスキーマをuseFormフックへ連携させます。useFormのオプションにあるresolverプロパティに、zodResolverを指定してください。
React Hook Formは、送信時や入力時にスキーマを参照してチェックを実行します。この手法により、UIコンポーネント側のコードを常にクリーンな状態に保てるでしょう。
- useFormの引数にresolver zodResolverを渡す
- TypeScriptの場合はuseFormのジェネリクスに型を指定する
この設定だけで、入力値が不適切な場合にエラー状態を自動で管理してくれます。
④ 条件に応じてエラーメッセージを表示する
最後に、発生したエラーをユーザーへフィードバックします。useFormから取得できるformStateの中には、errorsオブジェクトが含まれています。
ここには制約に違反したフィールド名とメッセージが格納されます。React-hook form watchなどで状態を監視しつつ、適切に表示しましょう。
- errorsのフィールドが存在する場合にのみメッセージを表示する
- Zodのスキーマ側でmessageプロパティを指定し、文言をカスタマイズする
- 複数の条件がある場合も、Zodが適切なメッセージを自動返却する
errorsオブジェクトを参照して条件分岐を行えば、親切なUIが完成します。複雑な相関バリデーションも、Zodを活用すれば柔軟に実装できるはず。
React Hook Formを実務に導入するポイント
実務に導入する際は流行を追うだけでなく、プロジェクトの規模や要件に合わせて最適なタイミングで採用してください。最新のReactエコシステムにおいて、React Hook Formを効果的に活用する具体的なポイントを解説します。
既存のライブラリから移行する判断基準
既存の実装やFormikなどからReact Hook Formへ移行する最大の判断基準は、レンダリングコストと保守性です。本ライブラリはRefを利用して値を管理するため、入力のたびにコンポーネント全体が再レンダリングされるのを防げます。
移行を検討すべき具体的な基準を以下の表にまとめました。
| 評価項目 | 移行を推奨するケース | 移行を急がないケース |
|---|---|---|
| パフォーマンス | 項目が多くタイピング時に遅延を感じる | 小規模なログインフォームのみである |
| コードの記述量 | ボイラープレートが多くロジックが複雑 | シンプルなReact stateで完結している |
| バリデーション | Zodなど外部スキーマ連携が必要 | 検証がほぼ不要または極めて単純 |
| 外部ライブラリ | MUI等のUIライブラリと親和性を高めたい | 独自実装のinputタグのみで構成されている |
多数の入力項目がある場合や複雑なReact-hook form validationが要求される現場では、導入により開発効率が劇的に向上します。React-hook-form インストールを検討し、モダンな開発環境を整えましょう。
複数ステップのフォームを実装するコツ
複数ステップのフォームを実装する場合、ステップ間の状態維持とバリデーションのタイミング制御が重要です。ステップを跨いだ広範な共有が必要な場面では、React Contextで状態共有 する設計と組み合わせるのも有効ですし、フォーム内に閉じる場合はReact-hook form watch機能やuseFormContextを活用すれば、ステップをまたいだ動的な表示制御が容易になります。
実装のコツとして、以下のポイントを意識してください。
- FormProviderを使用してネストされたコンポーネント間で状態を共有する
- React-hook form watchを利用して入力内容に応じた項目の表示を制御する
- useFormのmodeオプションでバリデーション実行のタイミングを最適化する
検証タイミングはユーザー体験に直結するため、要件に応じて以下の設定を使い分けます。
| mode設定 | 検証タイミング | 適したケース |
|---|---|---|
| onSubmit | 送信ボタン押下時 | ユーザーの入力を妨げない標準設定 |
| onBlur | フォーカスが外れた時 | 早期にエラーを通知したい場合 |
| onChange | 入力のたびに検証 | リアルタイムなフィードバックが必要な場合 |
レンダリングの最適化を計測する方法
React Hook Formを導入する大きな目的は、不要なレンダリングの削減です。その効果を客観的に計測するには、React DevToolsのProfilerタブを活用してください。
計測の主な手順と確認ポイントは以下の通りです。
- Profilerでフォーム入力中の再レンダリング回数と処理時間を記録する
- Highlight Updatesを有効化し、入力時に不要な親コンポーネントが反応していないか目視する
- useStateによる制御コンポーネント実装と、React Hook Formによる実装の負荷差を比較する
本ライブラリは値を入力しても、基本的にトップレベルの再レンダリングを発生させません。もし頻繁な再レンダリングが確認される場合は、React-hook form Controllerのラップ範囲が広すぎる可能性があります。
まとめ:React Hook Formで効率的なフォーム開発を実現しよう
React Hook Formは、軽量でパフォーマンスに優れたフォーム実装を可能にするライブラリです。基本的な使い方はもちろん、Controllerを使った外部ライブラリとの連携や配列操作など、幅広いシーンで活用できます。
インストールも簡単で、setValueやwatchといった関数を使いこなせば複雑な状態管理もスムーズです。さらにZodと組み合わせたバリデーション設定により、堅牢なフォームを最小限のコードで構築できるでしょう。
本記事のポイント
- 非制御コンポーネントの活用により、無駄な再レンダリングを抑えて高速に動作する
- registerやhandleSubmitなどの直感的なAPIで、実装コードを大幅に削減可能
- Zodなどの外部ライブラリと柔軟に連携し、複雑なバリデーションも容易に管理できる
このライブラリを導入すれば、フォーム開発における煩雑な記述から解放されます。メンテナンス性の向上だけでなく、操作性の改善はユーザーの信頼獲得にもつながるはずです。
まずはプロジェクトの一部から導入し、その柔軟な設計を実際に現場で体感してください。具体的な実装方法や技術選定にお悩みの方は、ぜひ専門チームへの相談も検討しましょう。
参考文献
執筆者
編集部
Next.jsやAIを活用したモダンWeb開発・SEO実装に関する情報を発信。SEOに最適化したモダンWebサイト制作、設計ノウハウ、構造化データや内部リンク設計などを中心に扱っています。
監修者
MT Templates 代表/編集長
海外メディア企業でSEOエディターとして従事後、独立。複数メディア運営の経験をもとに、Next.jsやAIを活用したWeb開発・SEO技術を発信。リード獲得につながるサイト構築からSEO設計まで一貫したサポートを提供している。
関連記事
Reactのライフサイクルの仕組みとuseEffectでの実装【図解】
旧機能の廃止や再描画に悩む方へ、Reactのライフサイクルを図解し、useEffect等のフックによるアンマウント制御を学ぶことで、最適な実装が可能です。
Reactのコンポーネントの作り方・分け方・設計【初心者向け】
Reactのコンポーネントの適切な分け方や作り方に悩む方へ、種類や使い方、設計、ライブラリまで解説し、実務で活きる高保守性コード習得を導きます。
ReactのUIライブラリ人気7選・要件別の徹底比較【プロ解説】
UI開発に悩む方へ、人気のReactのUIライブラリを解説し、Material UI等の活用で技術的負債を防ぎ、美しいUIデザインによる保守性の高い開発を実現します。
useMemoの使い方・使わない基準とは?useCallbackとの違い
ReactでuseMemoの用途にお悩みですか。useCallbackやuseEffectとの違い、使わない基準を解説。不要な再レンダリングを防ぎ、アプリを最適化できます。
ReactとRedux入門・Toolkitの全5つの実装手順【初心者向け】
ReactでReduxを導入したい方向けに、ToolkitやTypeScriptでの実装手順から使わない条件まで解説し、実務的な状態管理スキルが身につく入門記事です。
ReactのContextの使い方とアンチパターン【プロが徹底解説】
ReactのContextでPropsバケツリレーを解消する使い方を解説。再レンダリングのアンチパターンやReduxとの比較を通じ、保守性の高い実装が可能です。