🌊

React用の簡単なバリデーションライブラリを作りました

2021/10/05に公開

はじめに

React を用いた Web アプリケーション開発において、Form のバリデーションをどうするかという問題に遭遇しました。
React Hook FormFormikなどいろんなライブラリを比較・検討してきましたが、
そこまで大きな機能は必要なく簡単なバリデーションができればいいという考えからライブラリを自作しました。

https://github.com/wattanx/react-svl

欲しかった機能

バリデーションライブラリの機能として欲しかったのは

  • バリデーションのルールを指定できる
  • Controlled Components を利用する
  • 必須チェック、最小・最大値チェック、最大・最小文字長チェック

使い方

まずはインストールします。

npm install react-svl

or

yarn add react-svl react

ここでは、Chakra UI を使って解説します。

example.tsx
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.プロパティ名.isInvalidtrueを返します。

<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

これまで紹介したソースコードを実際に動かすと下記のようになります。

最後に

パフォーマンスなどは全く考慮できていないので今後はそのあたりを改善していったり、
他のライブラリを参考にもう少し拡張していきたいと思っています。

簡単なバリデーションの実装の参考になれば幸いです。

https://github.com/wattanx/react-svl

参考

検討したバリデーションのライブラリ

  • React Hook Form

https://react-hook-form.com/

  • Formik

https://formik.org/docs/overview

  • Zod

https://github.com/colinhacks/zod

GitHubで編集を提案

Discussion