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

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

final-formformikreact-final-formredux-formはすべてReactアプリケーションにおけるフォーム管理を支援するライブラリですが、設計思想や統合方法に大きな違いがあります。final-formはフレームワーク非依存のコアロジックを提供し、react-final-formはそのReact向けバインディングです。formikはReact専用に最適化された高レベルAPIを提供し、直感的な使いやすさが特徴です。一方、redux-formはReduxストアにフォーム状態を保存する設計を採用していましたが、現在は非推奨となっています。これらのライブラリは、フォームの状態管理、バリデーション、サブミット処理、パフォーマンス最適化といった共通の課題に対して、それぞれ異なるアプローチで解決策を提供しています。

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

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
formik3,760,08134,387585 kB8364ヶ月前Apache-2.0
final-form577,7853,044382 kB969ヶ月前MIT
redux-form398,03412,5181.45 MB4973年前MIT
react-final-form07,440215 kB3749ヶ月前MIT

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

Reactアプリケーションでフォームを扱う際、状態管理やバリデーション、サブミット処理など多くの課題があります。final-formformikreact-final-formredux-formはそれぞれ異なるアプローチでこれらの課題に取り組んでいますが、設計思想や統合方法には大きな違いがあります。この記事では、実際の開発現場での使い勝手を中心に、各ライブラリの技術的特徴を比較します。

🧠 コア設計思想:スタンドアロン vs フレームワーク統合

final-formフレームワーク非依存の純粋なJavaScriptライブラリ です。Reactだけでなく、VueやAngularなど他のUIフレームワークでも利用可能です。内部でフォーム状態(値、エラー、dirtyフラグなど)を管理し、サブスクライブ可能なオブジェクトを提供します。

// final-form: 純粋なJS API
import { createForm } from 'final-form';

const form = createForm({
  onSubmit: values => console.log(values)
});

form.subscribe(state => {
  console.log('Current values:', state.values);
}, { values: true });

formikReact専用に最適化された高レベルAPI を提供します。useFormikフックや<Formik>コンポーネントを通じて、フォームロジックを宣言的に記述できます。状態管理からバリデーション、サブミット処理まで一貫したインターフェースを提供します。

// formik: React専用API
import { useFormik } from 'formik';

function MyForm() {
  const formik = useFormik({
    initialValues: { email: '' },
    onSubmit: values => alert(JSON.stringify(values, null, 2))
  });

  return (
    <form onSubmit={formik.handleSubmit}>
      <input
        name="email"
        onChange={formik.handleChange}
        value={formik.values.email}
      />
      <button type="submit">Submit</button>
    </form>
  );
}

react-final-formfinal-formReact向けバインディング です。final-formのコアロジックを活かしつつ、Reactコンポーネントとして使いやすいようにラップしています。

// react-final-form: final-formのReactバインディング
import { Form, Field } from 'react-final-form';

const MyForm = () => (
  <Form
    onSubmit={values => console.log(values)}
    render={({ handleSubmit }) => (
      <form onSubmit={handleSubmit}>
        <Field name="email">
          {({ input }) => <input {...input} />}
        </Field>
        <button type="submit">Submit</button>
      </form>
    )}
  />
);

redux-formReduxストアにフォーム状態を保存する設計 を採用しています。すべてのフォームデータがReduxのstateツリー内に存在し、通常のReduxアクションで操作されます。

// redux-form: Redux統合
import { reduxForm, Field } from 'redux-form';

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

export default reduxForm({
  form: 'myForm' // Redux state内のフォーム識別子
})(MyForm);

⚠️ 重要: redux-formは公式npmページで**非推奨(deprecated)**と明記されています。新規プロジェクトでの使用は避けてください。

📦 状態管理アーキテクチャ:どこにデータを置くか

各ライブラリはフォーム状態を異なる場所に保存します。これはアプリケーション全体のアーキテクチャに大きな影響を与えます。

final-formreact-final-formフォームインスタンス内に状態を保持 します。ReduxやContext APIとは独立しており、メモリ内で完結します。

// final-form: 内部状態管理
const form = createForm({ /* ... */ });
// 状態はformインスタンス内に閉じている

formik も同様に コンポーネントのローカル状態(useState相当)に保存 します。ただし、enableReinitializeオプションを使うことで外部propsからの再初期化も可能です。

// formik: ローカル状態
const formik = useFormik({
  initialValues: props.initialData, // 外部から初期値を受け取れる
  enableReinitialize: true // props変更時に再初期化
});

redux-formReduxストアの特定のパスに状態を保存 します。例えばform.myForm.valuesのようにアクセス可能で、他のReduxアクションからも操作できます。

// redux-form: Reduxストア内に保存
// store.getState().form.myForm.values

この違いは以下のような実践的な影響をもたらします:

  • パフォーマンス: final-form/formikはフォーム外の再レンダリングの影響を受けにくい
  • デバッグ: redux-formはRedux DevToolsで状態を追跡できるが、ストアが肥大化しやすい
  • テスト: final-form/formikはReduxのモック不要で単体テストが容易

🔌 バリデーションの実装方法

バリデーションはフォームライブラリの重要な機能ですが、各ライブラリのアプローチは異なります。

final-formreact-final-form同期・非同期バリデーション関数を直接渡す 方式を採用しています。

// final-form: バリデーション関数
const validate = values => {
  const errors = {};
  if (!values.email) errors.email = 'Required';
  return errors;
};

const form = createForm({ validate });

formik も同様に validate関数またはYupスキーマ をサポートしています。

// formik: Yupによるバリデーション
import * as Yup from 'yup';

const formik = useFormik({
  validationSchema: Yup.object({
    email: Yup.string().required('Required')
  })
});

redux-formvalidateプロップとして関数を受け取る 方式です。

// redux-form: バリデーション
const validate = values => {
  const errors = {};
  if (!values.email) errors.email = 'Required';
  return errors;
};

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

共通点として、すべてのライブラリがフィールド単位のリアルタイムバリデーションをサポートしていますが、formikはYupとの統合によりより宣言的なバリデーション記述が可能です。

🔄 パフォーマンス最適化:不要な再レンダリングを防ぐ

複雑なフォームでは、1つのフィールドの変更が全体を再レンダリングしてしまう問題が発生します。各ライブラリはこの問題に対処するための仕組みを提供しています。

final-form細かい粒度でのサブスクリプション をサポートしています。必要な状態だけを監視することで、不要な更新を回避できます。

// final-form: 細かいサブスクリプション
form.subscribe(state => {
  // emailフィールドの値だけを監視
}, { value: true, name: 'email' });

react-final-form はこの機能をReactコンポーネントとして提供します。<Field>コンポーネントはデフォルトで対応フィールドのみを再レンダリングします。

// react-final-form: 自動的な最適化
<Field name="email">
  {({ input, meta }) => (
    // emailフィールドの変更時のみ再レンダリング
    <input {...input} />
  )}
</Field>

formikuseFieldフック を使って個別のフィールド状態にアクセスできますが、デフォルトではフォーム全体の状態変更で再レンダリングが発生します。

// formik: useFieldで最適化
const EmailField = () => {
  const [field, meta] = useField('email');
  // フォーム全体ではなくemailフィールドのみの変更で更新
  return <input {...field} />;
};

redux-form はReduxの性質上、connectのメモ化やreselectの使用が必要 です。適切に最適化しないと、小さな変更でも大量の再レンダリングが発生します。

// redux-form: 手動最適化が必要
import { connect } from 'react-redux';

const mapStateToProps = (state, ownProps) => ({
  // reselectなどでメモ化が必要
  email: getFormValues(state).email
});

🧩 カスタムフィールドコンポーネントの作りやすさ

複雑なUI(日付ピッカー、オートコンプリートなど)をフォームに統合する際、カスタムフィールドコンポーネントの作成が重要になります。

react-final-formrender propパターン を採用しており、任意のコンポーネントにフォーム機能を注入できます。

// react-final-form: カスタムフィールド
const DatePickerField = ({ name }) => (
  <Field name={name}>
    {({ input }) => (
      <DatePicker
        selected={input.value}
        onChange={input.onChange}
      />
    )}
  </Field>
);

formikuseFieldフック を使って同じ目的を達成します。

// formik: カスタムフィールド
const DatePickerField = ({ name }) => {
  const [field, , helpers] = useField(name);
  return (
    <DatePicker
      selected={field.value}
      onChange={helpers.setValue}
    />
  );
};

redux-formFieldコンポーネントのcomponentプロップ でカスタムコンポーネントを指定できます。

// redux-form: カスタムフィールド
const renderDatePicker = ({ input }) => (
  <DatePicker
    selected={input.value}
    onChange={input.onChange}
  />
);

<Field name="date" component={renderDatePicker} />

final-form(スタンドアロン版)は直接DOM操作が必要になるため、Reactでのカスタムフィールド作成には向いていません。

📊 実践的な選択ガイド

小規模〜中規模アプリケーション

  • formik が最もバランスの良い選択肢です。学習コストが低く、豊富な機能と良好なTypeScriptサポートを備えています。

大規模アプリケーションでパフォーマンスが重要

  • react-final-form が優れた選択肢です。細かい再レンダリング制御と軽量なコアが、複雑なフォームでもスムーズな動作を実現します。

既存のReduxアプリケーション

  • redux-formは使用しないでください。代わりにformikまたはreact-final-formを採用し、必要に応じてReduxとの連携を手動で実装してください。

フレームワーク非依存が必要

  • final-form コアを使用し、各UIフレームワーク向けに独自のバインディングを作成します。

💡 まとめ:各ライブラリの位置付け

ライブラリ主な特徴推奨用途
final-formフレームワーク非依存、軽量コア複数フレームワーク対応が必要なケース
formikReact専用、高レベルAPI、Yup統合多くのReactプロジェクトに最適
react-final-formfinal-formのReactバインディング、細かい最適化パフォーマンスが重要な大規模フォーム
redux-form非推奨、Redux統合新規プロジェクトでは使用しない

現代のReact開発においては、formikreact-final-form が主要な選択肢となります。プロジェクトの規模、パフォーマンス要件、チームの熟悉度を考慮して選択してください。

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

  • formik:

    formikを選ぶべきは、大多数のReactプロジェクトにおいてバランスの取れたソリューションが欲しい場合です。学習コストが低く、直感的なAPI、豊富な機能(Yupとのバリデーション統合、Field配列サポートなど)、優れたTypeScriptサポートを備えています。小規模から中規模のアプリケーションで特に効果を発揮し、開発速度と保守性の両立が可能です。

  • final-form:

    final-formを選ぶべきは、React以外のUIフレームワーク(Vue、Angularなど)でも同じフォームロジックを使いたい場合です。純粋なJavaScript APIを提供するため、フレームワーク非依存のアーキテクチャが必要なプロジェクトに最適です。ただし、React専用の機能(フック、コンポーネント統合)は提供しないため、Reactでの開発効率はreact-final-formformikに劣ります。

  • redux-form:

    redux-formは公式に非推奨(deprecated)とされているため、新規プロジェクトでは絶対に使用しないでください。既存のReduxアプリケーションで使用されている場合は、formikまたはreact-final-formへの移行を検討すべきです。Reduxストアにフォーム状態を保存する設計は、ストアの肥大化やパフォーマンス問題を引き起こすことが多く、現代のReact開発のベストプラクティスから外れています。

  • react-final-form:

    react-final-formを選ぶべきは、大規模で複雑なフォームがあり、パフォーマンス(不要な再レンダリングの回避)が重要な場合です。final-formの軽量で効率的なコアを利用しつつ、Reactコンポーネントとして使いやすいインターフェースを提供します。細かい粒度での再レンダリング制御が必要な高度なユースケースに最適です。

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.