formik vs final-form vs react-hook-form vs redux-form
Reactフォームライブラリの技術的比較
formikfinal-formreact-hook-formredux-form類似パッケージ:

Reactフォームライブラリの技術的比較

final-formformikreact-hook-formredux-form はすべて React アプリケーションでフォームを管理するためのライブラリです。これらのライブラリは、フォームの状態管理、バリデーション、サブミット処理などの共通課題を解決しますが、アーキテクチャやパフォーマンス特性、API設計において明確な違いがあります。redux-form は Redux ストアに依存し、final-form はフレームワーク非依存のコアロジックを提供します。formik は React コンテキストとフックを活用した高レベルな抽象化を提供し、react-hook-form は uncontrolled コンポーネントとネイティブ DOM API を中心とした最適化されたアプローチを採用しています。

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

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
formik3,786,65534,385585 kB8355ヶ月前Apache-2.0
final-form03,045382 kB9710ヶ月前MIT
react-hook-form044,6321.28 MB1336日前MIT
redux-form012,5151.45 MB4973年前MIT

Reactフォームライブラリ徹底比較:final-form、formik、react-hook-form、redux-form

React でフォームを扱うのは一見簡単ですが、バリデーション、エラーハンドリング、パフォーマンス、テスト可能性などを考慮すると、専用ライブラリの導入が現実的です。ここでは、代表的な4つのフォームライブラリ — final-formformikreact-hook-formredux-form — を、実際の開発現場で直面する課題を中心に比較します。

重要: redux-formnpm ページ および GitHub リポジトリ で非推奨(deprecated)と明記されています。新規プロジェクトでは使用しないでください。

🧠 基本アーキテクチャ:Controlled vs Uncontrolled vs 外部ストア

formik:Controlled コンポーネント中心

formik は React の controlled コンポーネントモデルを全面的に採用しています。フォームの各フィールドの値は React の state で管理され、変更のたびに再レンダリングが発生します。

// formik
import { useFormik } from 'formik';

function MyForm() {
  const formik = useFormik({
    initialValues: { email: '' },
    onSubmit: values => alert(JSON.stringify(values, null, 2)),
    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-hook-form:Uncontrolled コンポーネント + Ref 登録

react-hook-form は、uncontrolled コンポーネントを基本とし、DOM の ref を使って値を直接取得します。これにより、ユーザー入力時の再レンダリングを最小限に抑えます。

// react-hook-form
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>
  );
}

final-form:フレームワーク非依存のエンジン

final-form 自体は純粋な JavaScript ライブラリで、UI フレームワークに依存しません。React で使うには react-final-form などのバインディングが必要です。内部では、フィールドの状態をサブスクリプションベースで管理します。

// final-form (with react-final-form)
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, errors }) => (
      <form onSubmit={handleSubmit}>
        <Field name="email">
          {({ input, meta }) => (
            <>
              <input {...input} />
              {meta.touched && meta.error && <div>{meta.error}</div>}
            </>
          )}
        </Field>
        <button type="submit">送信</button>
      </form>
    )}
  />
);

redux-form:Redux ストアに状態を保存(非推奨)

redux-form は、フォームの全状態(値、エラー、タッチ状態など)を Redux ストアに保存します。これは、大規模アプリでは不要な再レンダリングやメモリ消費を引き起こします。

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

const renderField = ({ input, meta: { touched, error } }) => (
  <>
    <input {...input} />
    {touched && error && <div>{error}</div>}
  </>
);

let MyForm = props => (
  <form onSubmit={props.handleSubmit(values => alert(JSON.stringify(values)))}>
    <Field name="email" component={renderField} />
    <button type="submit">送信</button>
  </form>
);

MyForm = reduxForm({ form: 'myForm' })(MyForm);

⚡ パフォーマンス:再レンダリングの制御

大規模フォームでの挙動

  • formik:デフォルトでは、1つのフィールドの変更がフォーム全体の再レンダリングを引き起こします。useFieldmemo による最適化は可能ですが、手間がかかります。
  • react-hook-form:フィールドは個別に登録され、変更があってもそのフィールドのみが影響を受けます。デフォルトで最適化されています。
  • final-form:サブスクリプション機能により、特定のフィールドの変更だけを監視できます。適切に設定すれば、再レンダリングを最小限に抑えられます。
  • redux-form:フォームの任意の変更が Redux ストアを更新し、接続されたすべてのコンポーネントが再レンダリングされる可能性があります。パフォーマンス上の問題が頻発します。

✅ バリデーションの柔軟性

同期・非同期バリデーションの実装

formikvalidate 関数または validationSchema(Yup など)で定義。非同期バリデーションは validate 関数内で Promise を返すことで可能。

// formik 非同期バリデーション
const validate = async (values) => {
  const errors = {};
  const exists = await checkEmailExists(values.email);
  if (exists) errors.email = 'このメールは既に使用されています';
  return errors;
};

react-hook-formregister のオプションで同期バリデーションを定義。非同期バリデーションは resolver または validate 関数で実装。

// react-hook-form 非同期バリデーション
<input
  {...register('email', {
    validate: async (value) => {
      const exists = await checkEmailExists(value);
      return exists ? 'このメールは既に使用されています' : true;
    }
  })}
/>

final-formvalidate 関数で同期バリデーション。非同期バリデーションは asyncValidate またはカスタムロジックで実装可能。

// final-form 非同期バリデーション(簡略化)
<Form
  validate={values => {
    // 同期バリデーション
  }}
  // 非同期はカスタムフックなどで対応
>

redux-formvalidate および asyncValidate プロップで対応可能でしたが、非推奨のため詳細は割愛。

🔌 TypeScript サポート

  • formik:v2 以降、TypeScript サポートが大幅に改善。initialValues の型から自動的にフォーム値の型が推論されます。
  • react-hook-form:ゼロランタイムコストで完全な TypeScript サポート。ジェネリクスでフォーム値の型を明示的に指定可能。
  • final-form:コアライブラリは TypeScript 対応。react-final-form も型定義を提供。
  • redux-form:型定義は存在しますが、非推奨のため今後の更新は期待できません。

🧪 テスト可能性

  • react-hook-form:DOM ベースのアプローチのため、React Testing Library との相性が非常に良い。fireEvent.change で直接入力値を操作可能。
  • formik:controlled コンポーネントのため、テストは直感的ですが、内部状態の操作には actwaitFor が必要になる場合があります。
  • final-form:テストは可能ですが、サブスクリプションモデルのため若干複雑になることがあります。
  • redux-form:Redux ストアのモックが必要で、テストセットアップが煩雑です。

📦 依存関係と拡張性

  • formik:React 専用。Yup との統合が一般的。
  • react-hook-form:React 専用。Resolver 経由で Yup、Zod、Joi など多数のバリデーションライブラリと連携可能。
  • final-form:フレームワーク非依存。React、Vue、Angular などさまざまなバインディングがコミュニティ提供。
  • redux-form:Redux に強く依存。現代の React アーキテクチャには不向き。

🆚 まとめ:選択の指針

観点final-formformikreact-hook-formredux-form
推奨度◯(特定用途向け)◯(小〜中規模フォーム)◎(ほとんどのケース)✗(非推奨)
パフォーマンス良(サブスクリプション制御)普(最適化要)優(デフォルトで最適化)悪(ストア依存)
学習コスト中(抽象度高)低(直感的)中(uncontrolled 概念)低(だが非推奨)
TypeScript可(非推奨)
拡張性優(フレームワーク非依存)良(Yup 統合)優(多様な resolver)悪(Redux 依存)

💡 最終的なアドバイス

  • 新規プロジェクト:まず react-hook-form を検討してください。パフォーマンス、DX、TypeScript サポートのバランスが最も優れています。
  • 既存の Redux アプリで小規模フォームformik がシンプルで導入しやすいでしょう。
  • 複数の UI フレームワークで共通ロジックを使いたいfinal-form のコアエンジンを活用できます。
  • redux-form を使っているプロジェクト:早急に移行を検討しましょう。final-formredux-form の作者が後継として開発したもので、移行パスも比較的スムーズです。

フォームはユーザー体験の要です。適切なライブラリを選ぶことで、開発速度とアプリケーションの品質を両立できます。

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

  • formik:

    formik は、controlled コンポーネントを中心に据え、開発体験を重視するプロジェクトに最適です。TypeScript サポートが充実しており、バリデーションスキーマ(Yup など)との統合も容易です。ただし、大規模なフォームでは再レンダリングのオーバーヘッドが発生しやすいため、パフォーマンス要件が高い場合は注意が必要です。

  • final-form:

    final-form は、フレームワークに依存しない軽量なフォームエンジンを必要とする場合に適しています。特に、React 以外の UI ライブラリ(例:Vue、Svelte)と統合したい場合や、独自の React バインディングを構築したい場合に有効です。ただし、React 専用の高レベル API は提供しないため、追加のラッパー実装が必要になることがあります。

  • react-hook-form:

    react-hook-form は、uncontrolled コンポーネントとネイティブ DOM API を活用することで、最小限の再レンダリングと高速なパフォーマンスを実現します。特に複雑で大規模なフォームや、パフォーマンスが重要なアプリケーションに強く推奨されます。また、TypeScript との親和性も高く、バリデーションルールを直感的に記述できます。

  • redux-form:

    redux-form は公式に非推奨(deprecated)とされており、新規プロジェクトでの使用は避けるべきです。Redux ストアにフォーム状態を保存するアーキテクチャは、不要な再レンダリングやメモリ使用量の増加を引き起こすことが多く、現代の React アプリケーションには不向きです。既存の redux-form を使っているプロジェクトは、final-formreact-hook-form への移行を検討すべきです。

formik のREADME

Formik.js

Build forms in React, without the tears.


Stable Release Blazing Fast gzip size license Discord

Visit https://formik.org to get started with Formik.

Organizations and projects using Formik

List of organizations and projects using Formik

Authors

Contributing

This monorepo uses yarn, so to start you'll need the package manager installed.

To run E2E tests you'll also need Playwright set up, which can be done locally via npx playwright install. Afterward, run yarn start:app and in a separate tab run yarn e2e:ui to boot up the test runner.

When you're done with your changes, we use changesets to manage release notes. Run yarn changeset to autogenerate notes to be appended to your pull request.

Thank you!

Contributors

Formik is made with <3 thanks to these wonderful people (emoji key):


Jared Palmer

💬 💻 🎨 📖 💡 🤔 👀 ⚠️

Ian White

💬 🐛 💻 📖 🤔 👀

Andrej Badin

💬 🐛 📖

Adam Howard

💬 🐛 🤔 👀

Vlad Shcherbin

💬 🐛 🤔

Brikou CARRE

🐛 📖

Sam Kvale

🐛 💻 ⚠️

Jon Tansey

🐛 💻

Tyler Martinez

🐛 📖

Tobias Lohse

🐛 💻

This project follows the all-contributors specification. Contributions of any kind welcome!

Related

  • TSDX - Zero-config CLI for TypeScript used by this repo. (Formik's Rollup configuration as a CLI)

Apache 2.0 License.