formik vs react-final-form vs react-hook-form vs react-jsonschema-form
React 表单管理ライブラリのアーキテクチャ比較と選定ガイド
formikreact-final-formreact-hook-formreact-jsonschema-form類似パッケージ:

React 表单管理ライブラリのアーキテクチャ比較と選定ガイド

formik、react-final-form、react-hook-form、react-jsonschema-form は、React アプリケーションにおけるフォーム状態管理、バリデーション、および提交処理を効率化するための主要なライブラリです。それぞれが異なる設計思想に基づいており、単純な入力収集から複雑な動的フォーム、あるいはスキーマ駆動型の自动生成まで、多様な要件に対応します。開発者はプロジェクトの規模、パフォーマンス要件、およびフォームの動的性質に応じて、最適なツールを選択する必要があります。

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

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
formik034,310585 kB8441年前Apache-2.0
react-final-form07,435263 kB3786ヶ月前MIT
react-hook-form044,8821.64 MB72日前MIT
react-jsonschema-form015,924-1487年前Apache-2.0

React フォームライブラリ徹底比較:アーキテクチャ、パフォーマンス、そして適切な選択

React 開発において、フォーム管理は避けて通れない課題です。formik、react-final-form、react-hook-form、react-jsonschema-form は、それぞれ異なる哲学を持ってこの問題にアプローチしています。単に「動く」ものを選ぶのではなく、アプリケーションの規模や要件に合ったアーキテクチャを選択することが、長期的なメンテナンス性を決定づけます。

🏗️ 基本アーキテクチャ:状態管理のアプローチ違い

各ライブラリは、フォームの状態をどこで、どのように保持するかという点で根本的に異なります。

formik は、コンポーネントの状態としてフォームデータを管理します。useFormik フックまたは HOC を使用し、値、エラー、提交状態を単一のオブジェクトにまとめます。

// formik: コンポーネント内の状態管理
import { useFormik } from 'formik';

function 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 は、外部ストア(Redux のような概念)で状態を管理し、サブスクリプションパターンを通じてコンポーネントにデータを流します。これにより、フォームの状態ロジックが UI から完全に分離されます。

// react-final-form: サブスクリプションベースの管理
import { Form, Field } from 'react-final-form';

function MyForm() {
  return (
    <Form
      onSubmit={values => console.log(values)}
      render={({ handleSubmit }) => (
        <form onSubmit={handleSubmit}>
          <Field name="email">
            {({ input, meta }) => (
              <input {...input} placeholder="Email" />
            )}
          </Field>
        </form>
      )}
    />
  );
}

react-hook-form は、内部で参照(Ref)を直接使用し、React の状態更新トリガーを最小限に抑えます。これが驚異的なパフォーマンスの源であり、不要な再レンダリングを発生させません。

// react-hook-form: 参照ベースで再レンダリングを回避
import { useForm } from 'react-hook-form';

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

  return (
    <form onSubmit={handleSubmit(data => console.log(data))}>
      <input {...register('email')} placeholder="Email" />
    </form>
  );
}

react-jsonschema-form は、JSON Schema オブジェクトを入力として受け取り、自動的にフォーム UI を生成します。状態管理はライブラリ内部で完結しており、開発者はスキーマ定義に集中します。

// react-jsonschema-form: スキーマ駆動型の自动生成
import Form from '@rjsf/core';

const schema = {
  type: 'object',
  properties: {
    email: { type: 'string', format: 'email' }
  }
};

function MyForm() {
  return <Form schema={schema} onSubmit={({ formData }) => console.log(formData)} />;
}

⚡ パフォーマンス:再レンダリングの挙動

大規模フォームにおいて、入力時のラグはユーザー体験を損ないます。ここで各ライブラリの挙動が大きく分かれます。

formik と react-final-form は、デフォルトでは入力値の変更ごとにフォーム全体、あるいは関連コンポーネントを再レンダリングする傾向があります。formik では React.memo や useMemo を駆使して最適化する必要がありますが、設定が煩雑になることがあります。

// formik: 最適化しないと親が再レンダリングされる
// 入力たびに Form 全体が描画され直す可能性がある
const MyInput = ({ formik }) => (
  <input name="email" onChange={formik.handleChange} value={formik.values.email} />
);

react-hook-form は、登録された入力フィールドを直接 DOM 参照で制御するため、入力時の再レンダリングが発生しません。 submit やバリデーションエラー表示時など、本当に必要な時だけ更新がかかります。

// react-hook-form: 入力時は再レンダリングなし
// register により Ref が直接紐付くため、state 更新不要
<input {...register('email')} />

react-jsonschema-form は、内部実装に依存しますが、スキーマが複雑になるとレンダリングツリーが巨大化し、パフォーマンス低下のリスクがあります。動的なカスタマイズを加えるほど、最適化は難しくなります。

// react-jsonschema-form: 複雑な UI Schema で重くなる可能性
const uiSchema = {
  email: { 'ui:widget': 'email' }
};
// <Form schema={schema} uiSchema={uiSchema} />

🔍 バリデーションとエラーハンドリング

バリデーションロジックの記述方法も、ライブラリ選定の重要な要素です。

formik と react-hook-form は、Yup や Zod などのスキーマ検証ライブラリと柔軟に連携できます。特に react-hook-form は Resolver を介してこれらを統合し、型安全性を高めることができます。

// react-hook-form + Zod: 型安全なバリデーション
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

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

const { register, formState: { errors } } = useForm({
  resolver: zodResolver(schema)
});

// <input {...register('email')} />
// {errors.email && <span>{errors.email.message}</span>}
// formik + Yup: 一般的なパターン
import * as Yup from 'yup';

const formik = useFormik({
  validationSchema: Yup.object({ email: Yup.string().email() }),
  // ...
});

react-final-form は、バリデーション関数を props として渡す形式を取ります。これにより、バリデーションロジックを完全に制御できますが、ボイラープレートが増える傾向があります。

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

<Field name="email" validate={validate}>
  {({ input, meta }) => (
    <>
      <input {...input} />
      {meta.touched && meta.error && <span>{meta.error}</span>}
    </>
  )}
</Field>

react-jsonschema-form は、JSON Schema 仕様自体にバリデーション規則が含まれているため、追加のコードなしで標準的な検証が行われます。ただし、カスタムロジックを組み込むには独自の拡張机制が必要です。

// react-jsonschema-form: スキーマ定義内でバリデーション
const schema = {
  properties: {
    email: { 
      type: 'string', 
      format: 'email', 
      minLength: 5 
    }
  }
};
// フォームは自動的にこれらの規則を検証します

🛠️ 動的フォームと拡張性

フィールドの追加・削除や、条件付き表示といった動的な挙動への対応力も比較ポイントです。

react-hook-form は useFieldArray フックを提供しており、配列フィールドの操作(追加、削除、入れ替え)を非常に効率的に行えます。パフォーマンス劣化を気にせず大規模なリストを扱えます。

// react-hook-form: 配列フィールドの効率的な処理
const { fields, append, remove } = useFieldArray({ name: 'users' });

{fields.map((field, index) => (
  <div key={field.id}>
    <input {...register(`users.${index}.name`)} />
    <button type="button" onClick={() => remove(index)}>Delete</button>
  </div>
))}

formik も配列操作をサポートしていますが、ヘルパー関数(arrayHelpers)を使用する必要があり、実装が少し重くなることがあります。

// formik: arrayHelpers を使用
<FieldArray name="users">
  {arrayHelpers => (
    <div>
      {values.users.map((user, index) => (
        <div key={index}>
          <Field name={`users.${index}.name`} />
          <button type="button" onClick={() => arrayHelpers.remove(index)}>
            Delete
          </button>
        </div>
      ))}
    </div>
  )}
</FieldArray>

react-jsonschema-form は、配列アイテムの追加・削除 UI を自動生成しますが、その見た目のカスタマイズには深い理解が必要です。一方、react-final-form はフィールドの動的追加を柔軟に扱えますが、状態管理の複雑さが増すため、設計に注意が必要です。

// react-jsonschema-form: 配列は自動生成される
// schema の type が 'array' の場合、追加ボタンなどが自動で付与される
const schema = {
  type: 'array',
  items: { type: 'string' }
};

📊 選定のまとめ

特徴formikreact-final-formreact-hook-formreact-jsonschema-form
学習曲線低い中〜高い中低い(スキーマ理解が必要)
パフォーマンス普通(最適化必要)普通非常に高い普通〜低い(規模による)
バンドルサイズ中中小大
動的フォーム可能(Helper 必要)柔軟容易 (useFieldArray)自動生成(カスタム難)
バリデーションYup/Zod 等と連携カスタム関数Resolver 経由で連携JSON Schema 標準準拠
主な用途汎用フォーム複雑な状態管理パフォーマンス重視設定画面・ビルダー

💡 結論:どのライブラリを選ぶべきか

現代の React 開発において、react-hook-form は、その優れたパフォーマンスと Hooks との親和性から、新規プロジェクトの第一選択肢として強く推奨されます。特に、入力フィールドが多いダッシュボードや、頻繁な更新が発生するアプリケーションでは、その差が顕著に現れます。

formik は、依然として強力な候補です。既存のコードベースとの整合性や、チームがコンポーネントベースの状態管理に慣れ親しんでいる場合には、スムーズな導入が可能です。

react-final-form は、フォームの状態ロジックを Redux のように厳密に管理したい特殊なケースや、サブスクリプションモデルの利点を活かしたい場合に真価を発揮します。

最後に、react-jsonschema-form は、他の 3 つとは目的が異なります。「フォームを作る」のではなく「スキーマからフォームを生成する」必要がある場合、これ一択となります。管理ツールの開発や、ユーザー定義フォームの実装など、特定のドメインで絶大な力を発揮します。

プロジェクトの要件を正しく見極め、適切なツールを選ぶことが、堅牢なフロントエンドアーキテクチャへの第一歩です。

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

  • formik:

    小規模から中規模のプロジェクトで、直感的な API と豊富なコミュニティリソースを優先する場合に formik を選定します。コンポーネントベースの設計に慣れているチームや、既存の ecosystem との統合を重視する際に適していますが、大規模フォームでの再レンダリング最適化には追加の工夫が必要です。

  • react-final-form:

    フォームの状態ロジックを UI コンポーネントから完全に分離し、テスト容易性や複雑な状態遷移を厳密に管理したい場合に react-final-form を採用します。Redux と同様のアーキテクチャパターンを好むチームや、サブスクリプションベースの細かな制御が必要なエンタープライズ向けアプリケーションに適しています。

  • react-hook-form:

    パフォーマンスを最優先し、特に大規模なフォームや頻繁な更新が発生するダイナミックな UI を扱う場合に react-hook-form が最適です。Hooks を活用して不要な再レンダリングを回避し、最小限のコード量で実装したい現代の React プロジェクトにおいて、事実上の標準選択肢となります。

  • react-jsonschema-form:

    ユーザーが動的にフォーム構造を定義する必要がある場合や、バックエンドのスキーマ定義から自動的にフォームを生成したい場合に react-jsonschema-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.