読者です 読者をやめる 読者になる 読者になる

かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

TypeScript + Reactのredux-formでサブミット時に検証を行う

redux-formのhandleSubmitに検証処理を渡すことでサブミット時に検証ロジックを走らせることができます。 こいつは、非同期前提なのでPromiseを返す感じのシグネチャになってます。

フォーム部分のコードの抜粋はこんな感じになります。validateContentメソッドが検証ロジックになります。引数にはフォームのデータとRedux.Dispatchが渡されてきます。Redux.Dispatchを使って、検証結果が正しい時や正しくないときに柔軟にアクションを発行することが出来るようになっています。

import * as React from 'react';
import * as ReduxForm from 'redux-form';
import * as Redux from 'redux';
import * as rootReducers from '../reducers/rootReducers';
import * as calcActions from '../actions/calcActions';

interface IndexPageProps extends ReduxForm.ReduxFormProps {
    lhs?: number;
    rhs?: number;
    answer?: number;
}

interface FormData {
    lhsField: string;
    rhsField: string;
}

class IndexPage extends React.Component<IndexPageProps, {}> {
    private validateContent(data: FormData, dispatch: Redux.Dispatch) {
        return new Promise((resolve, reject) => {
            var result = {} as FormData;
            if (!parseFloat(data.lhsField)) {
                result.lhsField = '数字で頼む'
                reject(result);
                return;
            }
            if (!parseFloat(data.rhsField)) {
                result.rhsField = '数字で頼む'
                reject(result);
                return;
            }

            dispatch(calcActions.setInput(parseFloat(data.lhsField), parseFloat(data.rhsField)));
            dispatch(calcActions.setAnswer(10));
            resolve();
        });
    }

    render() {
        const {
            handleSubmit,
            fields: {lhsField, rhsField},
            lhs,
            rhs,
            answer
        } = this.props;
        return (
            <form onSubmit={handleSubmit(this.validateContent)}>
                <div>
                    <input type='text' {...lhsField} />{lhsField.error && <span>{lhsField.error}</span>}
                    <br/>
                    <input type='text' {...rhsField} />{rhsField.error && <span>{rhsField.error}</span>}
                    <br/>
                    <input type='submit' />
                </div>
                <div>
                    <span>{lhs} + {rhs} = {answer}</span>
                </div>
            </form>
        );
    }
}

function select(state: rootReducers.AppState): IndexPageProps {
    return {
        lhs: state.calc.lhs,
        rhs: state.calc.rhs,
        answer: state.calc.answer
    };
}

export default ReduxForm.reduxForm({
    form: 'IndexForm',
    fields: ['lhsField', 'rhsField']
}, select)(IndexPage);

いい感じ。