React Hook Formの使い方・基礎編 useStateでの複雑なフォーム管理を卒業しよう
2026年03月13日 15時00分更新
本記事はFIXERが提供する「cloud.config Tech Blog」に掲載された「React Hook Form 基礎編:useStateでのフォーム管理を卒業しよう」を再編集したものです。
React Hook Formを使ってきて、慣れてきたので共有です!
1. はじめに:useStateでフォーム管理って大変...
Reactでフォームを作るとき、まずはuseStateで管理することが多いと思います。
ただ、入力項目が増えてくると「stateが増える」「onChangeが増える」「バリデーションが散らかる」など、だんだん辛くなってきます。
今回は、フォームの入力値を管理し、バリデーションも簡単に行えるReact Hook Formを紹介したいと思います。
2. useStateでフォームを作ってみる
コラム①:Reactとstateについて
stateは「コンポーネントが覚えている値」で、stateが更新されると、Reactはコンポーネントを再レンダリング。
フォームをuseStateで管理する場合、入力のたびにstate更新 → 再レンダリングが起きます。
コラム②:制御コンポーネントと非制御コンポーネント
制御コンポーネント(Controlled):valueをstateで(React側で)管理。
非制御コンポーネント(Uncontrolled):値をDOM側で保持し、必要なときにref属性で参照する。
React Hook Formは基本的に非制御として動作。制御コンポーネントとして値を管理することも可能。
2-1. シンプルなフォーム例(name / email)
まずはuseStateを使ったフォームの例です。
名前とメールアドレスを入力するだけのシンプルなものですが、stateを定義していたり、イベントを受け取る関数があったり、inputタグにも色々な属性があったりとシンプルな例でも「ごちゃごちゃ」感がありますよね。
実務では他のロジックのstateもあるので、とても見にくくなります。さらに、GitHub Copilotのようなコード生成AIを使えば、フォーム項目を簡単に追加できてしまいます。その手軽さゆえに、気づけばstateとonChangeハンドラのペアが大量に生成されてしまいます。
import React, { useState } from "react";
export const SampleFormUseState = () => {
// 管理する値を定義
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
// それぞれの状態をコンソールに出力(実際はAPI送信など)
console.log({ name, email });
};
return (
<form onSubmit={handleSubmit}>
<label>
Name
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Taro"
/>
</label>
<label>
Email
<input
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="taro@example.com"
/>
</label>
<button type="submit">Submit</button>
</form>
);
};
2-2. 項目が増えると何が起きる?
・入力項目ごとにstateが増える
・onChangeが増える(ほぼ同じ処理何度も書く)
・「ほぼ」というのが共通化しにくくて厄介
・エラー表示やバリデーションを追加すると、さらにstateやロジックが増える
・フォームのstate
・バリデーションエラーのstate
・その他のstate
3. React Hook Formで同じフォームを書き換える
3-1. インストール
まずはインストール!
npm install react-hook-form
3-2. 最小構成(register / handleSubmit)
こちらも先ほどの例をReact Hook Formで書き換えたものです。シンプル!綺麗!
register: input などの入力要素をReact Hook Formに登録するための関数。これにより、入力値の追跡やバリデーション(必須入力、文字数制限など)が簡単になる。
// 例:必須チェック
<input {...register("name") , { required: true }} placeholder="Taro" />
handleSubmit: フォームの送信イベント(onSubmit)でこの関数を使うことで、送信前に自動でバリデーションが実行される。バリデーションが成功した場合にのみ、引数に渡した関数(例では onSubmit)が、フォームのデータ(data)を引数に受け取って実行される。
以下のように第二引数にも関数を渡すことができ、バリデーションエラーが発生した際に実行される。
// onError: エラーハンドリング関数
<form onSubmit={handleSubmit(onSubmit, onError)}>
import React from "react";
import { useForm } from "react-hook-form";
// フォームで扱う型を定義
type FormData = {
name: string;
email: string;
};
export const SampleFormRHF = () => {
const { register, handleSubmit } = useForm<FormData>();
const onSubmit = (data: FormData) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>
Name
<input {...register("name")} placeholder="Taro" />
</label>
<label>
Email
<input {...register("email")} placeholder="taro@example.com" />
</label>
<button type="submit">Submit</button>
</form>
);
};
4. 何が嬉しいのか
・入力項目ごとにuseStateを書かなくてよい
・onChangeハンドラを大量に書かなくてよい
・フォームが大きくなっても管理が破綻しにくい
・型と入力コンポーネントを追加するだけで良い
・非制御ベースなので、不要な再レンダリングを抑えやすい
5. まとめ
小さいフォームならuseStateでも十分ですが、項目が増えると途端に管理が大変になります。
React Hook Formは「フォームはフォーム専用ライブラリに任せる」という選択肢を提供してくれるので、実務でもかなり助かります。
竹内一真/FIXER
24卒で入社しました!「かずま」ではなく「いっしん」と読みます。
身体に障害があり電動車椅子に乗って生活しています。
卒業研究でPythonをメインに使っていましたが、それ以外にも趣味や授業でCやRuby, C#を少しだけ勉強してました。音楽制作や3Dモデリングに手を出していた時期もありました。何か作るのは好きな方だと思います。
趣味はアニメ鑑賞、音楽鑑賞、映画鑑賞、ゲームです!
よろしくお願いします!


この連載の記事
-
TECH
ミニPCサーバーにFluxを導入、GitOpsで自動デプロイする方法 -
TECH
MacでGitHub CLIの認証を行う方法 -
TECH
ゆるく理解する自作シェル実装1:そもそもシェルってどんなもの? -
TECH
プロンプトエンジニアリングのコツは「5W1Hを忘れずに」 -
TECH
GitHubの 超・超・超 基本的な使い方まとめ -
TECH
業務で使えるExcel関数テクニック − 関数を使った動的な範囲指定のコツ -
TECH
zshの初期設定がダサい…。表示内容を自分好みにカスタマイズしていく -
TECH
Proxmox VE+OpenMediaVaultで自宅用NASを作ってみた -
TECH
Chrome拡張はVue.jsで作るのがおすすめ -
TECH
gitコマンド、長いしだるいしMMS(マジ・短く・したい) -
TECH
Terraformのバージョン管理ツール、古いtfenvからtenvへの移行 - この連載の一覧へ


