Posted at

redux-formでFieldレベルのvalidateをやり方と気をつけること

More than 1 year has passed since last update.


環境


  • react ^16.3.2

  • react-redux ^5.0.7

  • redux ^4.0.0

  • redux-form ^7.3.0


FieldレベルでValidate

Redux Form - Synchronous Validation ExampleここでやっているようなValidateの方法もありますが、これだと汎用性に欠けるので僕は専らFieldレベルでValidateするようにしています。


component

FieldレベルでのValidateを実装する場合にはFieldにvalidateプロパティを渡すだけです。んで、配列になっているのでいくつもValidateメソッドを渡すことができます。

下記の場合であれば必須チェックとメールアドレスチェックですね。

import { Field, reduxForm } from 'redux-form'

import * as Validator from 'utils/validate'

const MyComponet = () => {
{/** 省略 **/}
}

render() {
return(
<Field
component={MyComponent}
name="email"
type="email"
floatingLabel="ユーザー名"
textSize={16}
icon={['fas', 'fa-envelope']}
validate={[Validator.email, Validator.required]}
/>
)
}


Validate.js

utils/Validate.jsとかで別ファイルで作って置くといいですね。

やってることは簡単で正規表現でチェックしてメッセージを出すかundefinedreturnします。

extendValidatorについてはちょっと説明が必要なので後述しますね。

const ErrorMessages = {

required: '必須項目です。',
email: '正しいメールアドレスの形式でご入力ください。',
password: '英字、数字を組み合わせた8文字以上16文字以内で入力。',
url: 'URLの形式が間違っています。 例:https://example.com'
}

const Regex = {
email: /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
password: /^(?=.*?[a-zA-Z])(?=.*?\d)[!-\~]{8,16}$/,
url: /^(https?)(:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)$/
}

export const required = value => (value || typeof value === 'number' ? undefined : ErrorMessages.required)

export const email = value => (value && !Regex.email.test(value) ? ErrorMessages.email : undefined)

export const password = value => (value && !Regex.password.test(value) ? ErrorMessages.password : undefined)

export const url = value => (value && !Regex.url.test(value) ? ErrorMessages.url : undefined)

export const extendValidator = text => func => (func ? text : undefined)


extendValidator

validateメソッドを拡張するメソッドです。なんで拡張する理由があるかというとエラーメッセージを変えたいなどに対応するためです。例えば・・・

ログインページでは必須チェックのメッセージを「必須項目です」ではなく「ログイン用のメールアドレスが入力されていません」といった感じで局所的に変更を加えたい場合などですね。


使い方

const exEmail = value => Validator.extendValidator('ちげーし')(Validator.email(value))

validate={[Validator.exEmail]}

とは言ってもこれでは拡張メソッドを新たに作る必要はないですよね。validateメソッドに引数で文言を渡せばいいじゃんとなりますもんね。実はredux-formのバージョンが新しくなって例えばrequired('ほげ')とvalidateに渡すことができなくなってしまったんです。なのでどうするかというと拡張メソッドを作るか、下記のような感じでもできます。

export const email = text => value => {

if (value && !Regex.email.test(value)) {
return text ? text : ErrorMessages.email
}
return undefined
}

validate={[(value) => Validator.email('違うし')(value)]}

ちなみにvalidateでは(value, values, props)を受け取ることができます。なので、パスワード確認とかも簡単にできます。

<Field

component={FieldInput}
name="password"
type="password"
validate={[Validator.password, Validator.required]}
classes={['u-mb-24']}
/>
<Field
component={FieldInput}
name="confirm"
type="password"
validate={[(value, values) => (
Validator.confirmPass(value)(values.password)
), Validator.required]}
/>

export const confirmPass = value => pass => {

if (value !== pass) {
return 'パスワードが違います'
}
return undefined
}