React フォーム設計で実務で迷いやすい状態管理とバリデーション

React フォーム設計で入力値管理とバリデーションを分ける図

フォームは小さく見えて責務が多い

React フォーム設計で実務上の問題になりやすいのは、入力値、バリデーション、送信処理、エラー表示が一つのコンポーネントに集まることです。

結論から言うと、フォームは「入力値を持つ場所」「検証する場所」「送信する場所」「エラーを表示する場所」を分けて考えます。

一方で、React Hook Formのようなライブラリは強力です。ただし、責務が曖昧なまま導入すると、ライブラリのAPIと業務ルールが密結合します。

Reactフォーム設計で分けたい4つの責務

責務主な内容レビュー観点
入力値管理value、onChange、dirty状態不要な再レンダリングが増えていないか
バリデーション必須、形式、範囲、相関チェックサーバー側ルールと矛盾しないか
送信処理API呼び出し、二重送信防止loadingとエラーが明確か
エラー表示項目エラー、全体エラー、APIエラーユーザーが次の操作を判断できるか

まず、Reactのinput制御は、React公式のinputリファレンスに基本があります。そのうえで、実務では業務ルールとAPI連携が乗ります。

失敗例:stateが増えすぎるフォーム

例えば、次のようなコードは初期実装ではよくあります。しかし、項目が増えると保守が重くなります。

const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [nameError, setNameError] = useState("");
const [emailError, setEmailError] = useState("");
const [serverError, setServerError] = useState("");
const [submitting, setSubmitting] = useState(false);

つまり、入力値、項目エラー、APIエラー、送信状態が並列に増えています。そのため、レビューでは状態の組み合わせが破綻しないかを確認する必要があります。

改善例:フォーム値と検証結果を分ける

type FormValues = {
  name: string;
  email: string;
};

type FieldErrors = Partial<Record<keyof FormValues, string>>;

function validate(values: FormValues): FieldErrors {
  const errors: FieldErrors = {};

  if (!values.name.trim()) errors.name = "名前を入力してください";
  if (!values.email.includes("@")) errors.email = "メールアドレスの形式を確認してください";

  return errors;
}

一方で、検証関数を分けると、UIから独立してテストできます。さらに、Zodのようなスキーマ検証を使えば、TypeScriptの型と実行時検証を近づけられます。なお、詳しくはZod公式ドキュメントが参考になります。

React Hook Formを使うべき場面

また、React Hook Formは、項目数が多いフォームや、再レンダリングを抑えたいフォームで有効です。公式情報はReact Hook Form公式サイトで確認できます。

状況判断理由
2、3項目の簡単な検索フォームuseStateで十分なことが多い導入コストが勝つ場合がある
項目数が多い入力フォームReact Hook Formを検討登録、検証、送信が整理しやすい
複雑な相関チェックがあるスキーマ検証と併用ルールをUIから分離できる
APIエラーが多い表示設計を別途決めるサーバー由来のエラーは別責務

送信処理とエラー表示を混ぜない

そこで、フォーム送信ではクライアントバリデーションとAPIエラーを分けます。前者は送信前に確認できます。一方で、後者はサーバーの結果です。

  • 送信中はボタンをdisabledにして二重送信を防ぐ
  • 項目エラーは入力欄の近くに出す
  • API全体エラーはフォーム上部に出す
  • 送信成功後の画面遷移やリセット条件を明確にする

さらに、エラー表示は技術というよりUXの問題でもあります。ユーザーが次に何を直せばよいか分からないエラーは、実装として動いていても業務画面としては不十分です。

レビューで確認したいチェックリスト

  • 入力値とエラー状態が責務別に整理されているか
  • バリデーションがUI内に散らばっていないか
  • React Hook Formを使う理由が明確か
  • APIエラーと項目エラーが混ざっていないか
  • 二重送信、戻る操作、初期値変更を考慮しているか
  • テストで検証関数と送信処理を確認できるか

まとめ:Reactフォーム設計は責務分離が先

最後に、React フォーム設計では、ライブラリ選定より先に責務を分けます。入力値、バリデーション、送信処理、エラー表示を分けると、変更に強くなります。

もちろん、React Hook Formは有効な選択肢です。ただし、業務ルールやAPIエラーまで無理に押し込むと、フォーム全体が読みにくくなります。

React/TypeScript案件では、フォーム設計の品質が業務画面の使いやすさに直結します。入力画面、バリデーション、API連携の経験を活かせる案件を探したい方は、今の経験と希望を一度聞かせてください。

IaC INP PM PMO PMP UX Webディレクター インフラエンジニア キャリアチェンジ フロントエンドエンジニア