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

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

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

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

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
redux-form515,03812,4761.45 MB4964年前MIT
final-form03,047439 kB1045ヶ月前MIT
formik034,305585 kB8441年前Apache-2.0
react-hook-form044,8571.57 MB123日前MIT

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

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

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

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

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

formik:validate 関数または 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-form:register のオプションで同期バリデーションを定義。非同期バリデーションは resolver または validate 関数で実装。

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

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

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

redux-form:validate および 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 コンポーネントのため、テストは直感的ですが、内部状態の操作には act や waitFor が必要になる場合があります。
  • 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-form は redux-form の作者が後継として開発したもので、移行パスも比較的スムーズです。

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

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

  • redux-form:

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

  • final-form:

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

  • formik:

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

  • react-hook-form:

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

redux-form のREADME

redux-form


You build great forms, but do you know HOW users use your forms? Find out with Form Nerd! Professional analytics from the creator of Redux Form.


NPM Version NPM Downloads Build Status codecov.io Code Climate styled with prettier Twitter URL Patreon Backers on Open Collective Sponsors on Open Collective

redux-form works with React Redux to enable an html form in React to use Redux to store all of its state.


💰Psst!! Do you know React and Redux? Sign up with Triplebyte to get offers from top tech companies! 💰


⚠️ ATTENTION ⚠️

If you're just getting started with your application and are looking for a form solution, the general consensus of the community is that you should not put your form state in Redux. The author of Redux Form took all of the lessons he learned about form use cases from maintaining Redux Form and built 🏁 React Final Form, which he recommends you use if you are just starting your project. It's also pretty easy to migrate to from Redux Form, because the <Field> component APIs are so similar. Here is a blog post where he explains his reasoning, or there are two talks if you prefer video. Formik is also a nice solution.

The only good reason, in the author's view, to use Redux Form in your application is if you need really tight coupling of your form data with Redux, specifically if you need to subscribe to it and modify it from parts of your application far from your form component, e.g. on another route. If you don't have that requirement, use 🏁 React Final Form.

Installation

npm install --save redux-form

Documentation

🏖 Code Sandboxes 🏖

You can play around with redux-form in these sandbox versions of the Examples.

Videos

A Practical Guide to Redux Form – React Alicante 2017
A Practical Guide to Redux Form – React Alicante 2017
Abstracting Form State with Redux Form – JS Channel 2016
Abstracting Form State with Redux Form – JS Channel 2016

Contributors

This project exists thanks to all the people who contribute.

Backers

Thank you to all our backers! 🙏 [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]