redux-form (1) - Simple Form Example
redux-form (2) - Synchronous Validation Example
redux-form (3) - Field-Level Validation Example
redux-form (4) - Submit Validation Example
redux-form (5) - Initialize From State
redux-form (6) - ユーザ登録
ReactでForm componentを作るときに、とても便利な**redux-form**の説明です。
redux-formの概説についてはまず以下の記事を参考にしてください。
redux-form (1) - Simple Form Example
Synchronous Validation Example
Synchronous Validation Example - Getting Started With redux-form
redux-formを使うと、FormのValidationが簡単に実装できます。
今回はValidation function を使った、formの同期的なvalidationです。
validate関数はRedux state のvaluesを入力として、errorのobjectを返します。
同様にwarning function、以下の例ではwarn、を指定することもできます。
ソースを詳細に見ていくと、まず以下の例では、component propとして、renderField という関数が指定されてます。上の説明で言うと、2. stateless functionのパターンです。
またrenderFieldの引数(prop object)が、{ input, label, type, meta: { touched, error, warning } }となっていることに注意してください。inputとmeta以外のlabelとtypeがcustom propsです。
import React from 'react'
import { Field, reduxForm } from 'redux-form'
// *** validation function
const validate = values => {
const errors = {}
if (!values.username) {
errors.username = 'Required'
} else if (values.username.length > 15) {
errors.username = 'Must be 15 characters or less'
}
if (!values.email) {
errors.email = 'Required'
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = 'Invalid email address'
}
if (!values.age) {
errors.age = 'Required'
} else if (isNaN(Number(values.age))) {
errors.age = 'Must be a number'
} else if (Number(values.age) < 18) {
errors.age = 'Sorry, you must be at least 18 years old'
}
return errors
}
// *** warning function
const warn = values => {
const warnings = {}
if (values.age < 19) {
warnings.age = 'Hmm, you seem a bit young...'
}
return warnings
}
// *** component prop : 2. A stateless function
const renderField = ({
input,
label,
type,
meta: { touched, error, warning }
}) => (
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type} />
{touched &&
((error && <span>{error}</span>) ||
(warning && <span>{warning}</span>))}
</div>
</div>
)
const SyncValidationForm = props => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<form onSubmit={handleSubmit}>
<Field
name="username"
type="text"
component={renderField}
label="Username"
/>
<Field name="email" type="email" component={renderField} label="Email" />
<Field name="age" type="number" component={renderField} label="Age" />
<div>
<button type="submit" disabled={submitting}>
Submit
</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>
Clear Values
</button>
</div>
</form>
)
}
export default reduxForm({
form: 'syncValidation', // a unique identifier for this form
validate, // *** validation function
warn // *** warning function
})(SyncValidationForm)
以下のindex.jsでは、オリジナルから不要と思われるものを削除し、最低限のものだけを残し見やすくしました。
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { createStore, combineReducers } from 'redux'
import { reducer as reduxFormReducer } from 'redux-form'
const dest = document.getElementById('content')
const reducer = combineReducers({
form: reduxFormReducer // mounted under "form"
})
const store = createStore(reducer)
const showResults = values =>
new Promise(resolve => {
setTimeout(() => {
// simulate server latency
window.alert(`You submitted:\n\n${JSON.stringify(values, null, 2)}`)
resolve()
}, 500)
})
let render = () => {
const SyncValidationForm = require('./SyncValidationForm').default
ReactDOM.hydrate(
<Provider store={store}>
<h2>Form</h2>
<SyncValidationForm onSubmit={showResults} />
</Provider>,
dest
)
}
render()
実行画面
メールの入力エラーと、年齢が未入力で
年齢制限もしっかりチェックできています。
全てのチェックがパスしてsubmitが成功しました。
今回は以上です。