はじめに
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], 'パスワードが一致しません')
});
