React Hook Formを勉強したばかりの人がやりがちな誤った実装パターン3選
はじめに
私自身がReactを勉強したてで、バリデーション実装のためにReact Hook Formを勉強した際に経験した誤った実装パターンについて紹介します。
誤った実装パターンで覚えてしまうと読みにくいコードになったり、チーム開発で他のエンジニアに迷惑がかかる可能性があります。実際に私の現場でも、誤った実装が積み重なり大規模なリファクタが必要になったことがありました
React Hook Formとは
Reactでフォームを扱う際、バリデーションや入力管理を楽にしてくれるライブラリが React Hook Formです。公式ドキュメントにも「パフォーマンスが良い」「記述量が減る」と書かれており、人気が高いライブラリの一つです。
Reactを使って入力フォーム実装をする際にはぜひ覚えておきたいライブラリです。
ただし、初めて学んだときに「やってしまいがちな誤った実装」があります。
この記事では、私自身が個人開発やチーム開発で経験した React Hook Formの誤った使い方と改善例 を3つ紹介します。
これから学ぶ人が同じ落とし穴にはまらないように参考にしていただければと思います。
誤った実装パターン1:フォームの値を useState で管理してしまう
❌ 誤った実装例(抜粋)
// useStateで二重管理してしまう例
const [email, setEmail] = useState("");
<input value={email} {...register("email")} onChange={(e) => setEmail(e.target.value)} />
Reactを勉強すると、まず「状態管理=useState
」と覚えますよね。
そのため、フォームを実装するときにも「とりあえずuseStateで管理しよう」と考える方が多いと思います。
しかし、React Hook Formを使う場合には注意が必要です。
なぜ問題か?
React Hook Formは内部でフォームの状態をすべて管理してくれます。
register
を使えば、その項目は自動的にReact Hook Formの管理下に入ります。
ここでuseState
を併用すると 二重管理 が発生し、
-
useState
とregister
の両方で同じ値を持つため、どちらを正とすべきか分からなくなる - コードが煩雑になり、バグを生みやすい
- 大規模フォームやリファクタ時に大きな負担になる
といった問題が発生します。
では、正しい書き方を見てみましょう。
✅ 改善例(抜粋)
// 不要なonChangeとuseStateを削除
<input type="email" {...register("email")} />
これで十分です。
React Hook Formが値を管理してくれるので、余計なuseState
は必要ありません。
よくある質問:フォームの値はどう扱うの?
「じゃあ、フォームに入力された値はどうやって使えばいいの?」と思う方もいるでしょう。
React Hook Formでは以下の方法があります:
- 値を参照したいとき →
getValues
やwatch
を使う - 値を更新したいとき →
setValue
を使う
なので、追加でstateを準備する必要はありません。
誤った実装パターン2:setValue を毎回 onChange に書いてしまう
これは私が初めてReact Hook Formを使った時にやってしまった実装です。
当時は「入力値をフォームに反映するならsetValue
で書き換えればいい」と思い込んでいました。
そのため、onChange
にsetValue
を直接書き、送信時にはgetValues
で値を取り出す――という遠回りな書き方をしていました。
❌ 誤った実装例(抜粋)
const { getValues, setValue, handleSubmit, register } = useForm();
// 送信時の処理
const onSubmit = () => {
// ❌ 不要: getValuesで入力内容を取得
const userName = getValues("username");
console.log("入力されたユーザー名:", userName);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
{/* ❌ 不要: onChangeで毎回 setValue を呼び出している */}
<input
type="text"
{...register("username")}
onChange={(e) => setValue("username", e.target.value)}
/>
<button type="submit">送信</button>
</form>
);
なぜ問題か?
一見「フォームに入力された値をちゃんと保存できている」ように見えますが、以下の問題があります。
-
setValue
とgetValues
を毎回使うのは冗長で読みづらい -
register
が自動でやってくれる処理をわざわざ二重に書いている - 複雑なフォームになるとバグの温床になる
React Hook Form の基本思想は、
「入力はregister
に任せ、送信時はhandleSubmit
で受け取る」
です。
✅ 改善例(抜粋)
const { handleSubmit, register } = useForm();
const onSubmit = (data) => {
// ✅ 正しくは handleSubmit の data から受け取れる
console.log("入力されたユーザー名:", data.username);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
{/* registerを使えば自動で値が管理される */}
<input type="text" {...register("username")} />
<button type="submit">送信</button>
</form>
);
ポイントまとめ
-
setValue
は「外部から値をフォームにセットする必要がある場合」にだけ使う
例: APIで取得したユーザー名を初期表示する - 通常のフォーム入力は、
register
で十分 -
handleSubmit
のdata
引数を使えば、素直に入力値を受け取れる
つまり、普段のフォームは 「register
+ handleSubmit
」でシンプルに書ける ということです。
誤った実装パターン3:エラー表示を忘れる / formState.errors を使えない
これは私が初めてバリデーションを試したときにやってしまった失敗です。
register("email", { required: true })
と書けば、自動で「必須入力です」というメッセージが出てくれるものだと思い込んでいました。
実際には、エラーメッセージを明示的に書いてあげないとユーザーには何も表示されません。
当時は個人開発だったので、安易にconsole.log
やalert
でエラーを確認して「まあ動いてるしこれでいいか」と済ませてしまっていました。
❌ 誤った実装例(抜粋)
<input {...register("email", { required: true })} />
{/* エラーを表示していない */}
なぜ問題か?
バリデーションを設定しても、ユーザーに「どこで入力が間違っているのか」を伝えなければ意味がありません。
「必須なのに入力しなくても送信できる」と誤解を招いたり、入力ミスに気づかないまま送信してしまう可能性があります。
結果として、ユーザー体験が大きく低下してしまいます。
✅ 改善例(抜粋)
const { register, formState: { errors } } = useForm();
return (
<>
<input {...register("email", { required: "メールアドレスは必須です" })} />
{errors.email && <p>{errors.email.message}</p>}
</>
)
formState.errors
を活用すれば、どの項目でエラーが起きたのかをユーザーに丁寧に伝えることができます。
フォームは「入力しやすい」だけでなく「間違いに気づきやすい」ことも同じくらい重要です。
React Hook Form のエラーメッセージ表示をしっかり取り入れて、使いやすいフォームを作りましょう。
まとめ
今回は、React Hook Form を勉強したばかりの人がやりがちな誤った実装を3つ紹介しました。
- フォームの値を useState で管理してしまう
- setValue を毎回 onChange に書いてしまう
- エラー表示を忘れる / formState.errors を使えない
私自身がこれらの間違いを犯していた大きな原因は、初心者向けチュートリアルを鵜呑みにして「とりあえず動く」状態で満足してしまったことでした。
フォーム実装で大切なのは、「React Hook Form に任せられる部分は任せる」ことです。余計なコードを足すと保守性が下がり、かえってバグの温床になります。
おすすめの学び方としては、
- コードを書いたら人に見てもらう
- 他の人がどう実装しているかを観察する
ことを意識すると、無駄な実装やクセに気づきやすくなります。
これから React Hook Form を使い始める方は、ぜひ公式ドキュメントも併せてチェックしつつ、今回の内容を参考にしてみてください。
Discussion