このページの本文へ

FIXER Tech Blog - Development

React Hook Formの使い方・基礎編 useStateでの複雑なフォーム管理を卒業しよう

2026年03月13日 15時00分更新

文● 竹内一真/FIXER

  • この記事をはてなブックマークに追加
  • 本文印刷

 本記事は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モデリングに手を出していた時期もありました。何か作るのは好きな方だと思います。
趣味はアニメ鑑賞、音楽鑑賞、映画鑑賞、ゲームです!
よろしくお願いします!

カテゴリートップへ

この連載の記事