formik、react-final-form、redux-form は、React アプリケーションにおけるフォームの状態管理、バリデーション、 submission 処理を簡素化するための主要なライブラリです。formik は、コンポーネントの状態を内部で管理し、最小限の設定で迅速に実装できることを目指しています。react-final-form は、高性能な状態管理コア(Final Form)を採用し、レンダリング最適化に重点を置いています。一方、redux-form は、フォームの状態を Redux ストアに統合することで、グローバルな状態管理を一元的に行うアプローチを取りますが、現在はメンテナンスモードに入り、新規プロジェクトでの使用は推奨されていません。
React アプリケーションにおいて、フォーム処理は単なる入力収集を超え、状態管理、バリデーション、エラー表示、そしてパフォーマンス最適化という複雑な課題を伴います。formik、react-final-form、redux-form は、この課題に対して異なるアーキテクチャアプローチで解決を試みてきました。本稿では、これら 3 つのライブラリの内部動作、パフォーマンス特性、そして実装パターンを技術的に深掘りし、アーキテクチャ選定の指針を提供します。
フォームの状態をどこに保持するかは、アプリケーション全体のパフォーマンスと複雑性に直結します。
formik は、フォームの状態をコンポーネント内部の React State で管理します。
// formik: コンポーネント内部で状態を管理
import { useFormik } from 'formik';
const MyForm = () => {
const formik = useFormik({
initialValues: { email: '' },
onSubmit: values => console.log(values),
});
return (
<form onSubmit={formik.handleSubmit}>
<input
name="email"
onChange={formik.handleChange}
value={formik.values.email}
/>
</form>
);
};
react-final-form は、外部のストア(Final Form コア)を使用しますが、Redux は不要です。
// react-final-form: サブスクリプションベースの外部ストア
import { Form, Field } from 'react-final-form';
const MyForm = () => (
<Form
onSubmit={async (values) => console.log(values)}
render={({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<Field name="email">
{({ input, meta }) => (
<input {...input} placeholder="email" />
)}
</Field>
</form>
)}
/>
);
redux-form は、フォームの状態を Redux グローバルストアに完全に統合します。
// redux-form: Redux ストアに状態を保存
import { reduxForm, Field } from 'redux-form';
let MyForm = ({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<Field name="email" component="input" placeholder="email" />
</form>
);
MyForm = reduxForm({ form: 'myForm' })(MyForm);
入力時のユーザー体験(UX)は、ライブラリがどのように再レンダリングを処理するかによって大きく左右されます。
formik は、デフォルトでは入力値が変更されるたびにフォーム全体を再レンダリングします。
validateOnChange や validateOnBlur オプションで制御可能ですが、根本的な構造上、最適化には工夫が必要です。// formik: 最適化には manual な工夫が必要
const formik = useFormik({
initialValues: { firstName: '', lastName: '' },
validateOnChange: false, // バリデーション頻度を減らす
onSubmit: values => console.log(values),
});
// 各入力コンポーネントを React.memo でラップする等の対策が必要
react-final-form は、フィールドレベルのサブスクリプションにより、必要なコンポーネントのみを更新します。
// react-final-form: 自動的な最適化
// Field コンポーネントは、自分の値が変わった時だけ再レンダリングされる
<Field name="firstName">
{({ input }) => <input {...input} />}
</Field>
// lastName が変更されても、この firstName フィールドは更新されない
redux-form は、Redux ストアの更新フローに依存するため、オーバーヘッドが大きいです。
CHANGE アクションがdispatch され、Reducer が実行され、ストアが更新されます。pure: true などの設定が必要ですが、限界があります。// redux-form: アクションディスパッチのオーバーヘッド
// 入力ごとに以下のフローが発生:
// Input Change -> dispatch(CHANGE) -> Reducer -> Store Update -> Connect HOC -> Render
// このチェーンがパフォーマンスボトルネックになることが多い
バリデーションロジックの記述方法と、エラー表示の制御性も重要な選定基準です。
formik は、関数ベースまたはスキーマベース(Yup など)のバリデーションをサポートします。
// formik: 関数ベースのバリデーション
const validate = (values) => {
const errors = {};
if (!values.email) {
errors.email = 'Required';
}
return errors;
};
const formik = useFormik({ initialValues: { email: '' }, validate, onSubmit: ... });
// エラー表示
{formik.errors.email && <div>{formik.errors.email}</div>}
react-final-form は、バリデーション関数をフィールド単位またはフォーム単位で定義できます。
// react-final-form: フィールドレベルのバリデーション
const required = value => (value ? undefined : 'Required');
<Field name="email" validate={required}>
{({ input, meta }) => (
<div>
<input {...input} />
{meta.error && meta.touched && <span>{meta.error}</span>}
</div>
)}
</Field>
redux-form は、フォーム全体のバリデーション関数をReducer に渡す形式です。
// redux-form: フォーム全体のバリデーション関数
const validate = (values) => {
const errors = {};
if (!values.email) errors.email = 'Required';
return errors;
};
MyForm = reduxForm({ form: 'myForm', validate })(MyForm);
// エラー表示は props から取得
const MyForm = ({ handleSubmit, errors }) => (
<form onSubmit={handleSubmit}>
<Field name="email" component="input" />
{errors.email && <span>{errors.email}</span>}
</form>
);
ライブラリの選択には、長期的な保守性も考慮する必要があります。
redux-form は現在、事実上のメンテナンスモードにあります。
formik と react-final-form はともに活発にメンテナンスされています。
formik はコミュニティ規模が大きく、react-final-form はパフォーマンス重視の堅牢なアーキテクチャを持っています。| 特徴 | formik | react-final-form | redux-form |
|---|---|---|---|
| 状態管理 | React State (ローカル) | 外部ストア (サブスク) | Redux Store (グローバル) |
| 再レンダリング | 全体再レンダリング傾向 | フィールド単位 (最適化済) | Redux 更新フロー (重たい) |
| セットアップ | 最小限、簡単 | 中程度 | 複雑 (Redux 設定必須) |
| パフォーマンス | 小〜中規模フォーム向け | 大規模・複雑フォーム向け | 低速 (非推奨) |
| 保守状況 | 活発 | 活発 | メンテナンスモード (非推奨) |
フォームライブラリの選定は、プロジェクトの規模とパフォーマンス要件によって決まります。
formik は、スタートアップや中小規模のプロジェクト、そして開発スピードを最優先する場合に最適です。設定が簡単で、ドキュメントも豊富であり、標準的なフォーム要件のほとんどをカバーします。
react-final-form は、エンタープライズ級のアプリケーションや、数百のフィールドを持つような複雑なフォームを扱う場合に真価を発揮します。そのサブスクリプションモデルは、入力時のラグを排除し、滑らかなユーザー体験を保証します。
redux-form は、過去の遺産として捉えるべきです。 Redux でフォームを管理するメリットは、現代の React パターンとパフォーマンス要件の前にもはや存在しません。新規プロジェクトでは、より現代的で効率的な alternatives を選択することが賢明です。
最終的には、**「単純さが必要なら formik、極限のパフォーマンスが必要なら react-final-form」**という指針が、多くの現場で有効な判断基準となるでしょう。
小規模から中規模のプロジェクトで、設定の手間を減らして素早くフォームを実装したい場合に formik を選択します。React のローカル状態(useState/useReducer)で十分なケースや、複雑なパフォーマンス最適化が不要な場合に適しています。エコシステムが広く、サードパーティ製の UI ライブラリとの統合も容易です。
大規模なフォームや、入力による再レンダリングの頻発がパフォーマンスボトルネックになる可能性がある場合に react-final-form を選択します。フィールドレベルでの細かい制御や、サブスクリプションベースの最適化が必要な複雑なエンタープライズアプリケーションに適しています。Redux を使用していないプロジェクトでも高性能なフォーム管理を実現できます。
新規プロジェクトで redux-form を選択すべきではありません。このライブラリはメンテナンスモードに入っており、React の現代的なパターン(フックなど)への対応が遅れています。既存のレガシーコードベースで既に導入されている場合を除き、代わりに formik や react-final-form、あるいは React Hook Form などの現代的な代替案を検討してください。
Visit https://formik.org to get started with Formik.
List of organizations and projects using Formik
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!
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!