概要
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; } }