LoginSignup
0
1

More than 3 years have passed since last update.

redux-form (2) - Synchronous Validation Example

Last updated at Posted at 2019-06-30

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です。

src/SyncValidationForm.js
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では、オリジナルから不要と思われるものを削除し、最低限のものだけを残し見やすくしました。

src/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()

実行画面

メールの入力エラーと、年齢が未入力で

image.png

年齢制限もしっかりチェックできています。

image.png

全てのチェックがパスしてsubmitが成功しました。

image.png

今回は以上です。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1