あかね
React Hook Form超入門:初心者でもハマらない最短ルート
2026年02月23日
要約を生成中...
はじめに
カリキュラム内でも必須になっていて、フォーム管理でよく使用するReact Hook Form(以下RHF)ですが、最初どうやって使うのか難しいですよね。
私は4章のテキストで見たのでそれを見ながらやりましたが、しばらく難しいなって思っていました。
最近はレビューしていて同じコメントをよくしたり、自分が記憶にあるはまったポイントなど印象に残っていることがいくつかあります。
この記事では、useFormが返しているものを一通り整理しつつ、初心者がハマりやすいポイントもまとめます。
基本の使い方
基本的にまずこう書きますよね。
const { register,
handleSubmit,
setValue,
watch,
reset,
formState: { errors, isSubmitting }
} = useForm<FormType>();なんとなく分割代入して、なんとなく使っていませんか???
一個ずつ見ていきます!
RHFは「フォーム状態管理ライブラリ」
RHFは単なるバリデーションライブラリではありません。
入力値の管理
エラー状態の管理
送信状態の管理
これらをまとめて扱うフォーム状態管理ライブラリです。
つまり、useFormが返しているものはすべてフォーム状態を操作・参照するための道具のようなものです。
register
inputをReact Hook Formに「接続する」ための関数です。
registerを使うと、RHFはそのinputのrefを受け取り、DOMから直接値を取得します。
つまりRHFは、useStateで値を管理しているのではなく、ref経由で値を読みにいく設計です。
この仕組みによって、入力のたびに再レンダリングせずにフォーム値を管理できます。
RHFが「軽い」と言われる理由はここにあります。
再レンダリングなしで追跡できるようになります。
useState は一文字打つたびに画面全体を書き換えるけど、register は送信ボタンを押すまでRHFが裏で値を預かっておいてくれるイメージ
handleSubmit
バリデーションが通ったときだけonSubmitを実行するラッパー関数です。
私は最初ハマってたんですが、結構大事なポイントが
バリデーション成功 → onSubmit実行
バリデーション失敗 → onSubmitは呼ばれない
という仕組みです。
また、onSubmitの引数にはuseFormに渡した型引数のデータが入ってくることが保証されます。
ハマりポイント
onSubmit内の処理が走ってない → APIが動いていないと思い込む → onSubmit内にconsole.logを仕込む → ログが出ない(困惑)
こんな時にまず確認するべきはerrorsです。
handleSubmitが動かないのではなく、「バリデーションで止まっている」だけ、というケースが(私はw)非常に多いです。
何かがバリデーションエラー出ているとonSubmitに到達しないので、関数の外でconsole.logでerrors見てみると大抵何かエラー出てますw
type FormType = {
email: string;
};
const {
register,
handleSubmit,
formState: { errors }
} = useForm<FormType>();
const onSubmit = (data: FormType) => {
console.log(errors);//エラーがあるとここに到達しないから確認できない
};
console.log(errors);//onSubmitの外だったらエラー見れる
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register("email", { required: "メールは必須です" })}
/>
{errors.email && <p>{errors.email.message}</p>}
<button type="submit">送信</button>
</form>formState.errors
現在どのフィールドでエラーが発生しているかを保持しています。
フォームが「どこで止まっているのか」を教えてくれるのがerrorsです。
注意したいポイント
エラー表示UIを作っていない
errorsを確認していない
これは好ましくないと思います。
formを作成する時には必ず使用すると覚えておきたいです。
setValue
外部からフォームの値を変更するための関数です。
何か別のフォーム値の変更に伴って値を変えたいとかそういった時に使用することが多いです。
watch
フォームの値を監視します。
watchした値が変わると、コンポーネント(form全体)は再レンダリングされます。
注意したいポイント
なんでもwatchしてしまうことです!!
watchは監視している値が変わるたびにform全体を再レンダリングします。
使えない場合を除いてregisterなどのuncontrolledで制御できるものを使用したいです。
getValuesとの違い
getValuesは「現在の値を取得するだけ」です。
再レンダリングは発生しません。
つまり、
watch → 監視(再レンダリングあり)
getValues → 取得のみ(再レンダリングなし)
用途を分けて使う必要があります。
const value = watch("email"); // 値が変わると再レンダリング
const handleClick = () => {
console.log(getValues("email")); // 取得するだけ(再レンダリングなし)
};useWatchとの違い
useWatchは特定のフィールドだけを監視するためのフックです。
useWatchを使用しているコンポーネントからしたのコンポーネントのみが再レンダリングされます。
フォーム全体をwatchするよりも、パフォーマンスを意識した設計ができます。
規模が大きくなると、useWatchの理解が重要になります。
reset
フォームの状態を初期化(リセット)します。
送信成功後や、キャンセル時によく使われます。
resetは「状態」もリセットする、という理解が大切です。
setValueして値を上書きするのとは少し異なるので注意したいです。
resetは値+errors+isDirty等もまとめて初期化
setValueは値だけ変えて状態は残る
編集画面でAPIから取得した値をフォームに流し込む場合は、setValueを大量に呼ぶのではなくreset(data)を使うことが多いです。
isDirtyとは?
isDirtyは「初期値から変更があったかどうか」を示すフラグです。
フォームに一度でも変更が入るとtrueになります。
reset(newValues)を渡すと、その値が新しい基準値(defaultValues)になります。
そのため、直後のisDirtyはfalseになります。
formState.isSubmitting
送信中かどうかを示すフラグです。送信中はtrueになります。
よくあるハマりポイント
ボタンをdisableしていない
二重管理が起きる
isSubmittingを使えば、送信中の二重クリックを防ぐことができます。
実務では必須のフラグです。
ここだけuseStateにしちゃうのもあるあるですが、useFormで使えるものは使うようにしましょう!
二重管理はアンチパターンです!
まとめ
useFormが返しているものは、それぞれがフォーム状態を扱うための道具です。
なんとなく使うのではなく、
registerは登録
handleSubmitはバリデーション込み送信
errorsは停止位置
watchは監視
getValuesは取得のみ
setValueは外部操作
resetは初期化
isSubmittingは送信状態
こう整理して理解しておくと、デバッグが一気に楽になります。
まずはuseFormの返り値を、ちゃんと理解できると良いですが、使っているうちに慣れるので大丈夫です。焦らずたくさん書いて覚えていきましょう!!!

