React Hook Form は Reack のバリデーションライブラリの一つです。 Hook の名が示す通り関数コンポーネントの Hook 機能を使ってバリデーション用のモジュールを提供してくれます。
ホーム | React Hook Form – Simple React forms validation
yup はバリデーションルールを定義するためのライブラリです。メソッドチェーン的にルールを決定できます。
React Hook Form と yup を組み合わせることでフォームのバリデーション定義を分かりやすく作れます。
はじめる | React Hook Form – Simple React forms validation#スキーマバリデーション
【React】React Hook Form と yup でフォームのバリデーションを作る – 株式会社シーポイントラボ | 浜松のシステム・RTK-GNSS開発
これらの組み込みのルールでもそれなりのバリデーションができるのですが、作りこむとなるととても足りません。ルールを作り、yup に増やす必要があります。これは次のコードで実現できます。
/** rules/password.js ルール定義関数を記述したファイル */ // パスワード強度調査ライブラリ zxcvbn // @see https://github.com/dropbox/zxcvbn import * as zxcvbn from 'zxcvbn'; import {ValidationError, TestContext, } from 'yup'; // 与えられたパスワードに要求する zxcvbn でスコア化された強度の最低値 const ZXCVBN_SCORE_REQUIRE_MIN = 2; /** * パスワードルール * @param password * @return {true|ValidationError} */ export const passwordZxcvbnRule = function (password) { // この中での this は TestContext // zxcvbn を実行して強度チェック const res = zxcvbn(password); // スコアが定数以上ならば true return res.score >= ZXCVBN_SCORE_REQUIRE_MIN ? true // スコアが定数を下回った場合、yup 用のエラーオブジェクトを生成して返す : this.createError({message: res.feedback.suggestions[0],}) // this.createError: (params?: { path?: string; message?: string; params?: object }) => ValidationError; // 未定義部はルール適用先でよしなにしてくれます }
/** BaseYup.js プロジェクト用に改造した yup を export するファイル*/ import * as yup from 'yup'; import { passwordZxcvbnRule } from './rules/password'; // rules/password.js で定義したルールを zxcvbn と名付けて yup に追加 yup.addMethod(yup.string, 'zxcvbn', function() { return this.test('zxcvbn', '',passwordZxcvbnRule); }); export const BaseYup = yup;
/** form.jsx yup を使うフォーム */ import { BaseYup as yup } from '../validation/BaseYup'; import {useForm} from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers'; const schema = yup.object().shape({ // zxcvbn ルールを使うと宣言 password: yup.string().required().zxcvbn().label('パスワード'), }); export const PasswordForm = () => { const { register, handleSubmit, errors, getValues, setError } = useForm({ resolver: yupResolver(schema), defaultValues: {password:''}, }); const onSend = handleSubmit(() => { Object.keys(errors).length === 0 && パスワードをどこかに送る関数(); }); return ( <div> <label>パスワード</label> <input type='text' name='password' inputRef={register} /> <span>{errors.password?.message}</span> </div> ); }
こんな感じで、与えられた入力値を元に true|ValidationError を返す関数を yup.addMethod すると addMethod で定義した名前でルールを定義できます。この様にすると次の様なプログラムを動かせます。
複雑なルールの場合、エラーメッセージも複雑になりがちです。そういった際、ルール単位で処理を構築できる addMethod は程々の粒度で便利です。