react-hook-form vs yup vs formik vs vee-validate vs react-final-form vs redux-form
Reactフォーム管理とバリデーションライブラリの比較
react-hook-formyupformikvee-validatereact-final-formredux-form類似パッケージ:

Reactフォーム管理とバリデーションライブラリの比較

formikreact-final-formreact-hook-formredux-formvee-validateyup はすべて、Reactアプリケーションにおけるフォームの状態管理や入力バリデーションを支援するためのライブラリです。これらのパッケージは、フォームの複雑さを軽減し、開発者が再利用可能なコンポーネントや堅牢なバリデーションロジックを構築できるように設計されています。ただし、アーキテクチャやパフォーマンス特性、API設計、依存関係の有無などに大きな違いがあります。たとえば、yup は純粋なバリデーションスキーマ定義ライブラリであり、UIフレームワークとは独立していますが、他の5つはReactフォームとの統合を前提としています。また、redux-form は公式に非推奨とされており、新規プロジェクトでの使用は避けるべきです。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
react-hook-form26,736,42744,5631.25 MB12411日前MIT
yup10,021,05323,690270 kB2405ヶ月前MIT
formik3,797,32534,387585 kB8364ヶ月前Apache-2.0
vee-validate873,11711,241511 kB1349ヶ月前MIT
react-final-form498,4937,440215 kB3749ヶ月前MIT
redux-form400,39012,5221.45 MB4973年前MIT

Reactフォーム管理とバリデーションライブラリ:技術的深掘り比較

Reactアプリケーションでフォームを扱う際、単なる <input> の集合を超えて、状態管理・バリデーション・エラーハンドリング・サブミット制御などを一貫して扱う必要があります。この領域には複数の成熟したライブラリが存在しますが、それぞれ設計哲学やパフォーマンス特性、APIスタイルが大きく異なります。本稿では、6つの主要パッケージ — formikreact-final-formreact-hook-formredux-formvee-validateyup — を、実践的な観点から比較します。

💡 注:redux-formnpmページ および GitHubリポジトリ で明確に 非推奨(deprecated) とされており、新規プロジェクトでの使用は避けてください。以下では参考のために言及しますが、選択肢としては除外すべきです。

🧩 アーキテクチャとデータフロー:Controlled vs Uncontrolled

フォームライブラリの核心は、「フォームの状態をどのように管理するか」にあります。この点で、各ライブラリは大きく2つのアプローチに分かれます。

formikreact-final-form:Controlled ベース

これらは、フォームの全状態をReactのstate(または内部ストア)で管理し、各入力要素を「controlled component」として扱います。つまり、値の変更ごとにstateが更新され、再レンダリングが発生します。

// formik: Controlled コンポーネント
import { useFormik } from 'formik';

function MyForm() {
  const formik = useFormik({
    initialValues: { email: '' },
    onSubmit: values => alert(JSON.stringify(values)),
    validate: values => {
      const errors = {};
      if (!values.email) errors.email = '必須です';
      return errors;
    }
  });

  return (
    <form onSubmit={formik.handleSubmit}>
      <input
        name="email"
        value={formik.values.email}
        onChange={formik.handleChange}
        onBlur={formik.handleBlur}
      />
      {formik.touched.email && formik.errors.email ? (
        <div>{formik.errors.email}</div>
      ) : null}
      <button type="submit">送信</button>
    </form>
  );
}
// react-final-form: render props + controlled
import { Form, Field } from 'react-final-form';

const MyForm = () => (
  <Form
    onSubmit={values => alert(JSON.stringify(values))}
    validate={values => {
      const errors = {};
      if (!values.email) errors.email = '必須です';
      return errors;
    }}
    render={({ handleSubmit, pristine, invalid }) => (
      <form onSubmit={handleSubmit}>
        <Field name="email">
          {({ input, meta }) => (
            <>
              <input {...input} />
              {meta.touched && meta.error && <div>{meta.error}</div>}
            </>
          )}
        </Field>
        <button type="submit" disabled={pristine || invalid}>送信</button>
      </form>
    )}
  />
);

react-hook-form:Uncontrolled ベース

一方、react-hook-form は、Reactの「uncontrolled component」モデルを活用します。入力値はDOM内に保持され、必要なときだけ読み出されます。これにより、ユーザーのタイピング中に再レンダリングが発生せず、パフォーマンスが大幅に向上します。

// react-hook-form: uncontrolled コンポーネント
import { useForm } from 'react-hook-form';

function MyForm() {
  const { register, handleSubmit, formState: { errors } } = useForm();

  return (
    <form onSubmit={handleSubmit(data => alert(JSON.stringify(data)))}>
      <input
        {...register('email', { required: '必須です' })}
      />
      {errors.email && <div>{errors.email.message}</div>}
      <button type="submit">送信</button>
    </form>
  );
}

vee-validate:柔軟なアプローチ

vee-validate は、React向けに提供される useFielduseForm フックを通じて、controlled/uncontrolled の両方をサポートしますが、基本的にはcontrolled方式を推奨しています。

// vee-validate: Vue風のルールベース
import { useField, useForm } from 'vee-validate';
import * as yup from 'yup';

const schema = yup.object({
  email: yup.string().required('必須です')
});

function MyForm() {
  const { handleSubmit } = useForm({
    validationSchema: schema
  });

  const { value: email, errorMessage, handleChange } = useField('email');

  return (
    <form onSubmit={handleSubmit(values => alert(JSON.stringify(values)))}>
      <input
        name="email"
        value={email}
        onChange={handleChange}
      />
      {errorMessage && <div>{errorMessage}</div>}
      <button type="submit">送信</button>
    </form>
  );
}

yup:バリデーション専用

yup はフォームライブラリではなく、バリデーションスキーマを定義するための独立ライブラリです。上記のどのフォームライブラリとも組み合わせて使えます。

// yup: 純粋なバリデーションスキーマ
import * as yup from 'yup';

const schema = yup.object({
  email: yup.string().email().required()
});

// 例:formik と組み合わせる
schema.validate({ email: 'test@example.com' })
  .then(valid => console.log(valid))
  .catch(err => console.log(err.message));

redux-form:非推奨のcontrolled方式

歴史的な参考として、redux-form はReduxストアにフォーム状態を保存するcontrolled方式でした。しかし、現在は非推奨です。

// redux-form (非推奨)
import { reduxForm, Field } from 'redux-form';

const MyForm = ({ handleSubmit }) => (
  <form onSubmit={handleSubmit}>
    <Field name="email" component="input" />
    <button type="submit">送信</button>
  </form>
);

export default reduxForm({ form: 'myForm' })(MyForm);

⚡ パフォーマンス特性:再レンダリングの頻度

フォームのパフォーマンスは、主に「不要な再レンダリングがどれだけ少ないか」で決まります。

  • react-hook-form は、uncontrolled方式により、入力中の再レンダリングがほぼゼロです。これは大規模フォームやモバイル環境で顕著な利点になります。
  • formik は、デフォルトではフィールド変更ごとに全体が再レンダリングされます。<Field> コンポーネントや useField を使えば部分最適化は可能ですが、注意深い設計が必要です。
  • react-final-form は、render props の粒度で再レンダリングを制御でき、パフォーマンスは良好です。ただし、親コンポーネントの再レンダリングが子に波及する可能性があります。
  • vee-validate は、フィールド単位で状態を管理するため、他のcontrolledライブラリより再レンダリングは抑制されますが、react-hook-form ほどではありません。

🔌 バリデーション統合:同期・非同期・スキーマ

同期バリデーション

すべてのライブラリが同期バリデーションをサポートしていますが、記述方法が異なります。

  • formikvalidate 関数または validationSchema(Yupと連携)
  • react-final-formvalidate 関数
  • react-hook-form:ビルトインルール(required, minLength など)または yup/zod との統合
  • vee-validate:ルールベース(required, email)または yup スキーマ
  • yup:スキーマ定義のみ

非同期バリデーション

メールアドレスの重複チェックなど、API呼び出しを伴うバリデーションが必要な場合:

  • formikvalidate 関数内で async/await を使用可能
  • react-final-formasyncValidate オプションあり
  • react-hook-formregistervalidate オプションで非同期関数を指定可能
  • vee-validatesetFieldError と組み合わせて非同期処理を実装
// react-hook-form での非同期バリデーション例
const { register } = useForm();

<input
  {...register('email', {
    validate: async (value) => {
      const response = await fetch(`/api/check-email?email=${value}`);
      const exists = await response.json();
      return exists ? 'このメールは既に登録されています' : true;
    }
  })}
/>

🧪 TypeScriptサポート

  • react-hook-form:型定義が非常に洗練されており、フォーム値の型安全性が最高レベルです。
  • formik:v2以降でTypeScriptサポートが改善されましたが、一部のAPIで型のゆるさがあります。
  • yup:スキーマから型を推論する inferType が利用可能で、他のライブラリとの連携で強力です。
  • react-final-form:型サポートはありますが、render props のため型推論がやや煩雑です。
  • vee-validate:TypeScript対応は良好ですが、React向けの型定義はVue版ほど成熟していません。

📦 依存関係とバンドルサイズ

  • react-hook-form:依存なし。軽量で自己完結。
  • formikimmer に依存(内部で不変性操作に使用)。
  • yup@babel/runtime などに依存。
  • react-final-formfinal-form というコアパッケージに依存。
  • vee-validate:ルールセットが大きいとバンドルサイズが増加。

🛠️ 実用的なガイドライン

大規模フォーム or 高パフォーマンスが必須 → react-hook-form

ユーザー体験を最優先するモダンアプリでは、react-hook-form が最もバランスの取れた選択です。特に、リアルタイムバリデーションや多数の入力フィールドがある場合にその真価を発揮します。

複雑なフォームロジック(動的フィールド、ネスト) → formik

フォーム内に条件付きフィールドや動的リスト(例:複数の住所入力)が多い場合、formikuseFieldArraysetFieldValue が便利です。ただし、再レンダリングの最適化には注意が必要です。

既存のReduxアプリで軽量なフォーム → react-final-form

Reduxを使っているレガシーアプリで、フォームだけを置き換えたい場合に有効です。ただし、新規プロジェクトでは推奨しません。

バリデーションロジックの再利用 → yup + 任意のフォームライブラリ

サーバーサイドとクライアントサイドで同じバリデーションルールを使いたい場合、yup スキーマを共通化すると保守性が向上します。

非推奨ライブラリの扱い → redux-form は避ける

redux-form はメンテナンスされておらず、セキュリティリスクや互換性問題の原因になります。既存コードがある場合は、react-hook-form への移行を計画してください。

📊 まとめ:選択の指針

ライブラリ推奨用途パフォーマンス学習コスト状態管理方式
react-hook-form新規プロジェクト、高パフォーマンス要件⭐⭐⭐⭐⭐uncontrolled
formik複雑なフォームロジック⭐⭐☆controlled
react-final-formレガシーReduxアプリのフォーム置き換え⭐⭐⭐中〜高controlled
vee-validateルールベースのバリデーション重視⭐⭐⭐controlled
yupバリデーションスキーマの共通化N/AN/A(補助ライブラリ)
redux-form使用禁止controlled(非推奨)

💡 最終的なアドバイス

  • 新規プロジェクトでは、まず react-hook-form を試す。パフォーマンス、DX、TypeScriptサポートのバランスが最良です。
  • バリデーションロジックを分離したいなら yup を組み合わせる。これにより、テスト容易性と再利用性が向上します。
  • redux-form は過去の遺物。見つけたら、移行計画を立てましょう。

フォームはユーザー体験の要です。適切なツールを選ぶことで、開発速度とアプリの品質を同時に高めることができます。

選び方: react-hook-form vs yup vs formik vs vee-validate vs react-final-form vs redux-form

  • react-hook-form:

    react-hook-form は、パフォーマンスと開発体験を重視する現代のReactプロジェクトに強く推奨されます。uncontrolled コンポーネントを活用し、再レンダリングを劇的に削減します。TypeScriptサポートも優れており、シンプルなAPIで直感的に扱えます。ただし、完全な uncontrolled 方式のため、一部の高度な制御ロジックには工夫が必要です。

  • yup:

    yup は、フォームライブラリではなく、純粋なJavaScriptオブジェクトのバリデーションスキーマ定義ツールです。formikreact-hook-form と組み合わせて使われることが多く、型安全で宣言的なバリデーションロジックを実現できます。単体ではフォーム状態管理機能を持たないため、必ず他のフォームライブラリと併用してください。

  • formik:

    formik は、中規模から大規模なフォームで柔軟性と豊富な機能(フィールド配列、ネストされたオブジェクト、カスタムフックなど)が必要な場合に適しています。Context API を内部で使い、Redux などの外部ステート管理に依存しないため、導入が簡単です。ただし、高頻度の再レンダリングが発生しやすい点に注意が必要です。

  • vee-validate:

    vee-validate は、Vue.js由来の設計思想を持ちつつReactでも利用可能なバリデーション中心のライブラリです。ルールベースのバリデーションやi18n対応が強みで、UIコンポーネントとの疎結合が可能です。ただし、Reactエコシステムではややマイナーであり、コミュニティサポートは他より限定的です。

  • react-final-form:

    react-final-form は、高性能かつ宣言的なフォーム管理を求めるプロジェクトに最適です。render props パターンを採用しており、不要な再レンダリングを最小限に抑えられます。ただし、render props の記法は現代のReact開発ではやや古く感じられ、学習コストが若干高くなります。

  • redux-form:

    redux-form は公式に非推奨(deprecated)とされており、新規プロジェクトでは絶対に使用すべきではありません。既存のReduxベースのレガシーアプリケーションでしか使われず、メンテナンスも停止されています。代わりに react-hook-formformik への移行を検討してください。

react-hook-form のREADME

npm downloads npm npm Discord

Get started | API | Form Builder | FAQs | Examples

Features

Install

npm install react-hook-form

Quickstart

import { useForm } from 'react-hook-form';

function App() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm();

  return (
    <form onSubmit={handleSubmit((data) => console.log(data))}>
      <input {...register('firstName')} />
      <input {...register('lastName', { required: true })} />
      {errors.lastName && <p>Last name is required.</p>}
      <input {...register('age', { pattern: /\d+/ })} />
      {errors.age && <p>Please enter number for age.</p>}
      <input type="submit" />
    </form>
  );
}

Sponsors

We’re incredibly grateful to these kind and generous sponsors for their support!

Past Sponsors

Thank you to our previous sponsors for your generous support!

Backers

Thanks go to all our backers! [Become a backer].

Contributors

Thanks go to these wonderful people! [Become a contributor].





Documentation website supported and backed by Vercel