Redux Form で、クライアントバリデーションを実施する

概要

Redux用のフォームライブラリである、Redux Formを用いて、クライアントバリデーション(validation)を実施した備忘録。本記事では、Reactを用いたRedux及びReduxFormの使用を前提とする。比較的我流が多くて間違った使い方をしてる可能性もある。

gifは圧縮してるのでクリックで鮮明なバージョンを確認できます。

前提

以下環境で動作確認済み

debian 8.6
react 15.6
redux 3.7.2
react-redux 4.4.8
redux-form 6.8.0

validation用メソッドを用意する

以下のような各種validateメソッドを用意する。validateメソッドは、入力値と、失敗時のエラーメッセージを指定し、入力値に応じてエラーメッセージかundefinedを戻すようにする。これらのメソッドは、各フォームから必要に応じて利用できるように、exportしておく。

/**
 * ReduxFormバリデーション用のバリデーションメソッド集
 * 各メソッドは、先頭の引数で入力データを受け取り、undefinedかエラーメッセージを戻す
 */

// 入力必須
export const required = (value, msg) => !value ? msg : undefined;

// 数値
export const number = (value, msg) => value && isNaN(value) ? msg : undefined;

// 最大文字数
export const maxLength = (value, max, msg) => value && value.length > max ? msg : undefined;

// 最小文字数
export const minLength = (value, min, msg) => value && value.length < min ? msg : undefined;

// 最大値
export const maxNum = (value, max, msg) => value && value > max ? msg : undefined;

// 最小値
export const minNum = (value, min, msg) => value && value < min ? msg : undefined;

// フォーマット
export const format = (value, reg, msg) => value && !value.match(reg) ? msg : undefined;

// メールアドレス
export const email = (value, msg) => format(value, /^[\w+\-.]+@[a-z\d\-.]+\.[a-z]+$/i, msg);

validation機能付きのFieldコンポーネントを実装する

下記のRenderFieldコンポーネントは、ReduxForm用のFiledコンポーネントと、エラーメッセージを表示する仕組みをラッピングしたコンポーネント。input要素及び、select,textareaに対応し、必要に応じてclassNameやdisabled属性を引き継げるようにしている。

/**
 * ReduxFormのFieldと、エラーメッセージを出力する機能を組み合わせたテンプレート
 */
export class RenderField extends React.Component {
  render() {
    const { className, type, input, disabled, meta: {touched, error} } = this.props;
    return (
      <div className="inline">
        { type === 'textarea' ?
        <textarea className={className} {...input} type={type} disabled={disabled}/>
        : type === 'select' ?
        <select className={className} {...input} type={type} disabled={disabled}>{this.props.children}</select>
        :
        <input className={className} {...input} type={type} disabled={disabled}/>
        }
        {touched && error && <span className="form-error">{error}</span>}
      </div>
    );
  }
};

RenderFieldコンポーネントを、Validationを指定して描画

従来通りのReduxFormを使いつつ、実装したvalidateメソッドをRenderFieldコンポーネントに適用する。

RenderFieldコンポーネント及び使用するvalidateメソッドをimportしておく。本記事ではそれぞれvalidation.jsxにまとめて記述している。

import { RenderField, required, maxLength, datetime } from '../../validation';

ニックネームの入力の場合、以下のように、Fieldコンポーネントのcomponent属性にRenderFieldを指定し、validate属性にvalidateメソッドの呼び出しを配列で記述する。

<FormGroup>
  <ControlLabel>ニックネーム</ControlLabel>
  <Field
    className="nickname"
    name="nickname"
    type="text"
    component={RenderField}
    disabled={this.props.isViewMode}
    validate={[
      (v) => required(v, 'ニックネームを入力してください'),
      (v) => maxLength(v, 16, 'ニックネームは16文字以下で入力してください')
    ]}
  />
</FormGroup>

バリデーションエラー時はsubmitできなくする

Buttonコンポーネント(react-bootstrap)のdisabled属性に、ReduxFormのinvalid属性をバインドする。本記事ではreact-bootstrap使ってるけど、多分標準のbuttonでも問題ない。

<Button type="submit" block disabled={this.props.invalid}>
  保存
</Button>

エラーメッセージを装飾する

エラーメッセージにはform-errorクラスが付与されるようにしているので、scssで装飾する。

.form-error {
  color: $theme-red;
  font-size: 80%;
  &::before {
    display: inline-block;
    font: normal normal normal 14px/1 FontAwesome;
    font-size: inherit;
    text-rendering: auto;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    content: '\F06A';
    margin-right: 5px;
  }
}

デモ(再掲)

gifは圧縮してるのでクリックで鮮明なバージョンを確認できます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です