検証

Formik は、複雑な検証を伴うフォームを容易に管理できるように設計されています。Formik は、同期および非同期のフォームレベルとフィールドレベルの検証をサポートしています。さらに、Yup を介したスキーマベースのフォームレベル検証のサポートが組み込まれています。このガイドでは、上記のすべてについて詳細に説明します。

検証の種類

フォームレベルの検証

フォームレベルの検証は、関数が実行されるたびにフォームのすべての `値` とプロパティに完全にアクセスできるため、依存フィールドを同時に検証できるため便利です。

Formik でフォームレベルの検証を行うには、2 つの方法があります

  • `<Formik validate>` と `withFormik({ validate: ... })`
  • `<Formik validationSchema>` と `withFormik({ validationSchema: ... })`

`validate`

`<Formik>` と `withFormik()` は、同期または非同期関数を引数として受け取る `validate` という prop/オプションを受け取ります。

// Synchronous validation
const validate = (values, props /* only available when using withFormik */) => {
const errors = {};
if (!values.email) {
errors.email = 'Required';
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = 'Invalid email address';
}
//...
return errors;
};
// Async Validation
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const validate = (values, props /* only available when using withFormik */) => {
return sleep(2000).then(() => {
const errors = {};
if (['admin', 'null', 'god'].includes(values.username)) {
errors.username = 'Nice try';
}
// ...
return errors;
});
};

`<Formik validate>` の詳細については、API リファレンスを参照してください。

`validationSchema`

上記のように、検証はあなた次第です。独自のバリデーターを作成するか、サードパーティのライブラリを使用してください。The Palmer Group では、オブジェクトスキーマの検証に Yup を使用しています。JoiReact PropTypes によく似た API を備えていますが、ブラウザで使用するのに十分小さく、ランタイムでの使用に十分高速です。私たちは Yup をとても気に入っているので、Formik には Yup オブジェクトスキーマ用の特別な設定オプション/プロパティである `validationSchema` があります。これは、Yup の検証エラーを、キーが `値` と `touched` に一致するきれいなオブジェクトに自動的に変換します。この対称性により、エラーメッセージに関するビジネスロジックを簡単に管理できます。

プロジェクトに Yup を追加するには、NPM からインストールします。

npm install yup --save
import React from 'react';
import { Formik, Form, Field } from 'formik';
import * as Yup from 'yup';
const SignupSchema = Yup.object().shape({
firstName: Yup.string()
.min(2, 'Too Short!')
.max(50, 'Too Long!')
.required('Required'),
lastName: Yup.string()
.min(2, 'Too Short!')
.max(50, 'Too Long!')
.required('Required'),
email: Yup.string().email('Invalid email').required('Required'),
});
export const ValidationSchemaExample = () => (
<div>
<h1>Signup</h1>
<Formik
initialValues={{
firstName: '',
lastName: '',
email: '',
}}
validationSchema={SignupSchema}
onSubmit={values => {
// same shape as initial values
console.log(values);
}}
>
{({ errors, touched }) => (
<Form>
<Field name="firstName" />
{errors.firstName && touched.firstName ? (
<div>{errors.firstName}</div>
) : null}
<Field name="lastName" />
{errors.lastName && touched.lastName ? (
<div>{errors.lastName}</div>
) : null}
<Field name="email" type="email" />
{errors.email && touched.email ? <div>{errors.email}</div> : null}
<button type="submit">Submit</button>
</Form>
)}
</Formik>
</div>
);

`<Formik validationSchema>` の詳細については、API リファレンスを参照してください。

フィールドレベルの検証

`validate`

Formik は、`<Field>`/`<FastField>` コンポーネントまたは `useField` フックの `validate` プロパティを介してフィールドレベルの検証をサポートしています。この関数は同期または非同期(Promise を返す)にすることができます。デフォルトでは、`onChange` と `onBlur` の後に実行されます。この動作は、トップレベルの `<Formik/>` コンポーネントでそれぞれ `validateOnChange` および `validateOnBlur` プロパティを使用して変更できます。変更/ぼかしに加えて、すべてのフィールドレベルの検証は送信試行の開始時に実行され、結果はトップレベルの検証結果と深くマージされます。

注:`<Field>/<FastField>` コンポーネントの `validate` 関数は、マウントされたフィールドでのみ実行されます。つまり、フォームのフロー中にフィールドのマウントが解除された場合(例:Material-UI の `<Tabs>` は、ユーザーがいた前の `<Tab>` のマウントを解除します)、これらのフィールドはフォームの検証/送信中に検証されません。

import React from 'react';
import { Formik, Form, Field } from 'formik';
function validateEmail(value) {
let error;
if (!value) {
error = 'Required';
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value)) {
error = 'Invalid email address';
}
return error;
}
function validateUsername(value) {
let error;
if (value === 'admin') {
error = 'Nice try!';
}
return error;
}
export const FieldLevelValidationExample = () => (
<div>
<h1>Signup</h1>
<Formik
initialValues={{
username: '',
email: '',
}}
onSubmit={values => {
// same shape as initial values
console.log(values);
}}
>
{({ errors, touched, isValidating }) => (
<Form>
<Field name="email" validate={validateEmail} />
{errors.email && touched.email && <div>{errors.email}</div>}
<Field name="username" validate={validateUsername} />
{errors.username && touched.username && <div>{errors.username}</div>}
<button type="submit">Submit</button>
</Form>
)}
</Formik>
</div>
);

検証の手動トリガー

Formik を使用して、それぞれ `validateForm` および `validateField` メソッドを使用して、フォームレベルとフィールドレベルの検証を手動でトリガーできます。

import React from 'react';
import { Formik, Form, Field } from 'formik';
function validateEmail(value) {
let error;
if (!value) {
error = 'Required';
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value)) {
error = 'Invalid email address';
}
return error;
}
function validateUsername(value) {
let error;
if (value === 'admin') {
error = 'Nice try!';
}
return error;
}
export const FieldLevelValidationExample = () => (
<div>
<h1>Signup</h1>
<Formik
initialValues={{
username: '',
email: '',
}}
onSubmit={values => {
// same shape as initial values
console.log(values);
}}
>
{({ errors, touched, validateField, validateForm }) => (
<Form>
<Field name="email" validate={validateEmail} />
{errors.email && touched.email && <div>{errors.email}</div>}
<Field name="username" validate={validateUsername} />
{errors.username && touched.username && <div>{errors.username}</div>}
{/** Trigger field-level validation
imperatively */}
<button type="button" onClick={() => validateField('username')}>
Check Username
</button>
{/** Trigger form-level validation
imperatively */}
<button
type="button"
onClick={() => validateForm().then(() => console.log('blah'))}
>
Validate All
</button>
<button type="submit">Submit</button>
</Form>
)}
</Formik>
</div>
);

検証はいつ実行されますか?

ニーズに応じて `<Formik validateOnChange>` および/または `<Formik validateOnBlur>` プロパティの値を変更することにより、Formik が検証を実行するタイミングを制御できます。デフォルトでは、Formik は次のように検証メソッドを実行します

**「変更」イベント/メソッドの後**(`値` を更新するもの)

  • handleChange
  • setFieldValue
  • setValues

**「ぼかし」イベント/メソッドの後**(`touched` を更新するもの)

  • handleBlur
  • setTouched
  • setFieldTouched

送信が試行されるたびに

  • handleSubmit
  • submitForm

また、Formik のレンダー/注入されたプロパティを介して提供される命令型ヘルパーメソッドもあり、これらを使用して命令的に検証を呼び出すことができます。

  • validateForm
  • validateField

エラーメッセージの表示

エラーメッセージは、フォームの検証に依存します。エラーが存在し、検証関数が値/初期値に一致する形状のエラーオブジェクト(そうあるべきです)を生成する場合、依存フィールドエラーは errors オブジェクトからアクセスできます。

import React from 'react';
import { Formik, Form, Field } from 'formik';
import * as Yup from 'yup';
const DisplayingErrorMessagesSchema = Yup.object().shape({
username: Yup.string()
.min(2, 'Too Short!')
.max(50, 'Too Long!')
.required('Required'),
email: Yup.string().email('Invalid email').required('Required'),
});
export const DisplayingErrorMessagesExample = () => (
<div>
<h1>Displaying Error Messages</h1>
<Formik
initialValues={{
username: '',
email: '',
}}
validationSchema={DisplayingErrorMessagesSchema}
onSubmit={values => {
// same shape as initial values
console.log(values);
}}
>
{({ errors, touched }) => (
<Form>
<Field name="username" />
{/* If this field has been touched, and it contains an error, display it
*/}
{touched.username && errors.username && <div>{errors.username}</div>}
<Field name="email" />
{/* If this field has been touched, and it contains an error, display
it */}
{touched.email && errors.email && <div>{errors.email}</div>}
<button type="submit">Submit</button>
</Form>
)}
</Formik>
</div>
);

ErrorMessage コンポーネントを使用して、エラーメッセージを表示することもできます。

よくある質問

フォームが検証されているかどうかを確認するにはどうすればよいですか?

`isValidating` プロパティが `true` の場合

`null` をエラーメッセージとして返すことはできますか?

いいえ。代わりに `undefined` を使用してください。Formik は、空の状態を表すために `undefined` を使用します。`null` を使用すると、Formik の計算されたプロパティのいくつかの部分(たとえば、`isValid` など)は予期したとおりに機能しません。

検証をテストするにはどうすればよいですか?

Formik には Yup 検証の広範な単体テストがあるため、テストする必要はありません。ただし、独自の検証関数を作成している場合は、それらを単体テストする必要があります。Formik の実行をテストする必要がある場合は、それぞれ命令型の `validateForm` および `validateField` メソッドを使用する必要があります。

このページはお役に立ちましたか?

ニュースレターを購読する

最新の Formik のニュース、記事、リソースが受信トレイに送信されます。

Copyright © 2020 Formium, Inc. All rights reserved.