かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

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);

いい感じ。