React用の簡単なバリデーションライブラリを作りました
はじめに
React を用いた Web アプリケーション開発において、Form のバリデーションをどうするかという問題に遭遇しました。
React Hook Form
やFormik
などいろんなライブラリを比較・検討してきましたが、
そこまで大きな機能は必要なく簡単なバリデーションができればいいという考えからライブラリを自作しました。
欲しかった機能
バリデーションライブラリの機能として欲しかったのは
- バリデーションのルールを指定できる
- Controlled Components を利用する
- 必須チェック、最小・最大値チェック、最大・最小文字長チェック
使い方
まずはインストールします。
npm install react-svl
or
yarn add react-svl react
ここでは、Chakra UI を使って解説します。
import { Box } from '@chakra-ui/layout';
import { Input } from '@chakra-ui/input';
import { FormControl, FormErrorMessage, FormLabel } from '@chakra-ui/form-control';
import { useForm } from 'react-svl';
export const ValidationExample = () => {
const { errors, values, setFieldValue, validateField } = useForm({
initialValues: {
FirstName: '',
Password: '',
},
validationRules: {
FirstName: {
isRequired: true,
},
Password: {
minLength: 8,
},
},
});
return (
<Box>
<FormControl isInvalid={errors.FirstName.isInValid}>
<FormLabel>First Name</FormLabel>
<Input
value={values.FirstName}
onChange={(e) => setFieldValue('FirstName', e.currentTarget.value)}
onBlur={() => validateField('FirstName')}
/>
<FormErrorMessage>{errors.FirstName.isRequired?.message}</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.Password.isInValid}>
<FormLabel>Password</FormLabel>
<Input
value={values.Password}
onChange={(e) => setFieldValue('Password', e.currentTarget.value)}
onBlur={() => validateField('Password')}
/>
<FormErrorMessage>{errors.Password.minLength?.message}</FormErrorMessage>
</FormControl>
</Box>
);
};
react-svl
からは一つの Custom Hooks をインポートしています。
useForm
はバリデーションに必要な関数を提供したり、バリデーションルールを設定したりする Hooks です。
詳細
バリデーションルールの設定
まずは、バリデーションルールと初期値を設定します。
initialValues
の初期値、validationRules
にバリデーションルールを設定します。
これは欲しかった機能のバリデーションのルールを指定できる
を満たすために実装しました。
const { errors, values, setFieldValue, validateField } = useForm({
initialValues: {
FirstName: "",
Password: "",
},
validationRules: {
FirstName: {
isRequired: true,
},
Password: {
minLength: 8,
},
},
});
下記のような型を作成しているので、入力時に type safe に設定が可能です。
export type UseFormProps<T> = {
validationRules: ValidationRule<T>;
initialValues: T;
};
export function useForm<T extends { [key: string]: any }>({
initialValues,
validationRules,
}: UseFormProps<T>);
バリデーションルールとして設定できるのは下記の項目です。
プロパティ | 型 | 説明 |
---|---|---|
isRequired | boolean | 必須かどうか |
max | number | 最大値 |
min | number | 最小値 |
maxLength | number | 最大文字長 |
minLength | number | 最小文字長 |
validate | (value: T[keyof T]) => boolean | カスタムバリデーションルール(true: エラーあり、false: エラーなし) |
state の変更
react-svl
は Controlled Components にしたかったので、Input 要素に state を定義して onChange イベントを設定する必要があります。
setFieldValue(プロパティ名, セットしたい値)
を使うことでを使用しているので state の変更が可能です。
<Input
value={values.FirstName}
onChange={(e) => setFieldValue("FirstName", e.currentTarget.value)}
/>
Validation の実行
validateField(プロパティ名)
を使うことでバリデーションが実行されます。
<Input
value={values.FirstName}
onChange={(e) => setFieldValue("FirstName", e.currentTarget.value)}
onBlur={() => validateField("FirstName")}
/>
エラー情報の取得
errors
オブジェクトにエラー情報が格納されています。
バリデーションの実行の結果、エラーがあればerrors.プロパティ名.isInvalid
がtrue
を返します。
<FormControl isInvalid={errors.FirstName.isInValid}>
<FormLabel>First Name</FormLabel>
<Input
value={values.FirstName}
onChange={(e) => setFieldValue("FirstName", e.currentTarget.value)}
onBlur={() => validateField("FirstName")}
/>
<FormErrorMessage>{errors.FirstName.isRequired?.message}</FormErrorMessage>
</FormControl>
また下記のように、各バリデーションルールに対応したメッセージをデフォルトで設定するようになっています。(Custom Rule の場合はなし)
errors.プロパティ名.ルール名.message
でメッセージを取得することができます。
ルール | エラーメッセージ |
---|---|
isRequired |
{プロパティ名} is required. |
max |
{プロパティ名} must be less than or equal to {最大値} . |
min |
{プロパティ名} must be greater than or equal to {最小値} . |
maxLength |
{プロパティ名} must be less than or equal to {最大文字長} characters. |
minLength |
{プロパティ名} must be {最小文字長} characters or more. |
Demo
これまで紹介したソースコードを実際に動かすと下記のようになります。
最後に
パフォーマンスなどは全く考慮できていないので今後はそのあたりを改善していったり、
他のライブラリを参考にもう少し拡張していきたいと思っています。
簡単なバリデーションの実装の参考になれば幸いです。
参考
検討したバリデーションのライブラリ
- React Hook Form
- Formik
- Zod
Discussion