日本語
京都・けいはんな学研都市のソフトウエア開発・Webシステム
株式会社Coolware
(けいはんな学研都市)

FormikとYupによるReactフォームバリデーション実装例

はじめに

FormikとYupを組み合わせることで、Reactアプリケーションで堅牢なフォームバリデーションを実装することができます。本記事では、実際のプロジェクトでよく使用される具体的なバリデーション実装例を紹介します。

Formikとは

Reactでバリデーション付きのフォームを簡単に実装できるライブラリです。以下のような特徴があります:

  • フォームの状態管理を簡素化
  • バリデーションの実装を容易に
  • フォーム送信処理の標準化

詳しくは公式ドキュメント(https://formik.org/docs/overview)をご覧ください。

Yupとは

JavaScript用のオブジェクトスキーマバリデーションライブラリです。以下のような特徴があります:

  • スキーマベースのバリデーション
  • 型安全性の確保
  • チェーン可能なAPI
  • カスタムバリデーションの容易な実装
  • 複雑な相互依存関係の表現が可能

詳しくは公式ドキュメント(https://www.npmjs.com/package/yup)をご覧ください。

FormikとYupを合わせて使う理由

1.宣言的なバリデーションルール

Yupを使用することで、バリデーションルールを宣言的に記述できます:

  • コードの可読性が向上
  • バリデーションロジックの一元管理が容易

2.FormikとYupの統合メリット

  • Formikが提供するValidationSchemaプロパティにYupのスキーマを直接指定可能
  • バリデーションエラーの自動変換と表示
  • 非同期バリデーションのサポート
  • 相互依存するフィールドのバリデーションが容易

この組み合わせにより、堅牢で保守性の高いフォームバリデーションを実装することができます。また、チーム開発においても、統一された方法でバリデーションを実装できるため、コードの一貫性を保ちやすいという利点があります。

React Hook Formとの比較

フォームを作成する時の選択肢として挙げられるのがreact-hook-formです。これとの違い、またReact-hook-formを使用した方がいい時は以下の通りです:

  • Formikは学習曲線が緩やかで、シンプルなフォームに適しています
  • React Hook Formはパフォーマンスに優れ、大規模なフォームに向いています
  • コード量が少なく済む場合はReact Hook Formが有利です

Yupの頻出バリデーションルール

バリデーションルール()内のエラーメッセージは例
必須入力string().required(“必須入力です”)
文字数の一致string().length(X,”X文字で入力してください”)
文字数の制限string().max(X,”X文字以下で入力してください”)
文字の種類の一致string().matches()
メールアドレスstring().email()

よくあるバリデーション実装例

1メールアドレス

今回はPC、ブラウザ上でメールアドレスを入力する場合のバリデーション例を示す。基本的なメールアドレスのルールに加えて、アルファベットと記号(@,-,_,.)以外の入力を禁止にする。

import * as Yup from 'yup';

const validationSchema = Yup.object().shape({
  email: Yup.string()
    .required('メールアドレスを入力してください')
    .email('正しいメールアドレス形式で入力してください')
    .matches(
      /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
      '使用できない文字が含まれています'
    )
});

2他の値が入力された時、必須入力になる

Aの値とBの値は片方が入力されると、もう片方が必須入力になる。このようなフォームのバリデーション例を示す。

import * as Yup from 'yup';

const validationSchema = Yup.object().shape({
  fieldA: Yup.string().when('fieldB', {
    is: value => value && value.length > 0,
    then: schema => schema.required('Field Aは必須入力です'),
    otherwise: schema => schema
  }),
  fieldB: Yup.string().when('fieldA', {
    is: value => value && value.length > 0,
    then: schema => schema.required('Field Bは必須入力です'),
    otherwise: schema => schema
  })
}, [['fieldA', 'fieldB']]); // 循環参照を解決するために配列を追加

3パスワード

パスワードは確認のために2回入力されることが多い。このバリデーションはAとBの入力が一致していることを確認する。

import * as Yup from 'yup';

const validationSchema = Yup.object().shape({
  password: Yup.string()
    .required('パスワードを入力してください')
    .min(8, 'パスワードは8文字以上で入力してください')
    .matches(
      /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]/,
      'パスワードは英字・数字・記号を含める必要があります'
    ),
  confirmPassword: Yup.string()
    .required('確認用パスワードを入力してください')
    .oneOf([Yup.ref('password'), null], 'パスワードが一致しません')
});