redux-form (4)  - Submit Validation Example

[redux-form (1) - Simple Form Example](https://qiita.com/sand/items/5ef1564546c130080398)
[redux-form (2) - Synchronous Validation Example](https://qiita.com/sand/items/7c24d811b8459839f767)
[redux-form (3) - Field-Level Validation Example](https://qiita.com/sand/items/0ce4078ba6fb443f0a54)
[redux-form (4) - Submit Validation Example](https://qiita.com/sand/items/3913526199b509770c6c)
[redux-form (5) - Initialize From State](https://qiita.com/sand/items/24bf124106761b2a8ace)
[redux-form (6) - ユーザ登録](https://qiita.com/sand/items/1ebf763ce98f71af41ec)

---

ReactでForm componentを作るときに、とても便利な**[redux-form](https://redux-form.com/8.2.2/)**の説明です。

**redux-form**の概説についてはまず以下の記事を参考にしてください。

[redux-form (1) - Simple Form Example](https://qiita.com/sand/items/5ef1564546c130080398)


# Submit Validation Example


[Submit Validation Example](https://redux-form.com/8.2.2/examples/submitvalidation/) - [Getting Started With redux-form](https://redux-form.com/8.2.2/docs/gettingstarted.md/)


今回は、Submit時のエラー処理についてです。



今回はonSubmitがpropとして指定されていないので、以下のonSubmit関数(submit)をhandleSubmit()の引数として与えます。


```JSX:src/submit.js
import { SubmissionError } from 'redux-form'

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

function submit(values) {
  return sleep(1000).then(() => {
    // simulate server latency
    if (!['john', 'paul', 'george', 'ringo'].includes(values.username)) {
      throw new SubmissionError({
        username: 'User does not exist', // 個別のfieldエラー
        _error: 'Login failed!'          // form全体のエラー
      })
    } else if (values.password !== 'redux-form') {
      throw new SubmissionError({
        password: 'Wrong password', // 個別のfieldエラー
        _error: 'Login failed!'     // form全体のエラー
      })
    } else {
      window.alert(`You submitted:\n\n${JSON.stringify(values, null, 2)}`)
    }
  })
}

export default submit
```

ここで注目すべきは以下のコードです。submit関数がpromiseで、rejectで new SubmissionError({ field1: 'error', field2: 'error' })　というエラーを投げれば、それぞれのfield (field1, field2)にエラーが追加されます。下のコードではusernameのfieldにエラーが追加されます。_error は個別のfieldでなく、form全体のエラーを表示したいときに追加します。


```
      throw new SubmissionError({
        username: 'User does not exist', // 個別のfieldエラー
        _error: 'Login failed!'          // form全体のエラー
      })
```


wrapped componentは以下のようになっています。this.props.onSubmitは渡されてきていないので、直接submit関数をimportし、handleSubmitの引数にしています。


```JSX:src/SubmitValidationForm.js
import React from 'react'
import { Field, reduxForm } from 'redux-form'
import submit from './submit'

const renderField = ({ input, label, type, meta: { touched, error } }) => (
  <div>
    <label>{label}</label>
    <div>
      <input {...input} placeholder={label} type={type} />
      {touched && error && <span>{error}</span>}
    </div>
  </div>
)

const SubmitValidationForm = props => {
  const { error, handleSubmit, pristine, reset, submitting } = props
  return (
    // onSubmitがpropとして渡ってきていないので引数として与える
    <form onSubmit={handleSubmit(submit)}>
      <Field
        name="username"
        type="text"
        component={renderField}
        label="Username"
      />
      <Field
        name="password"
        type="password"
        component={renderField}
        label="Password"
      />
      {error && <strong>{error}</strong>}
      <div>
        <button type="submit" disabled={submitting}>
          Log In
        </button>
        <button type="button" disabled={pristine || submitting} onClick={reset}>
          Clear Values
        </button>
      </div>
    </form>
  )
}

export default reduxForm({
  form: 'submitValidation' // a unique identifier for this form
})(SubmitValidationForm)
```


index.jsはオリジナルを変えて最小限のものに修正してあります。


```JSX: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)

let render = () => {
  const SubmitValidationForm = require('./SubmitValidationForm').default
  ReactDOM.hydrate(
    <Provider store={store}>
        <h2>Form</h2>
        <SubmitValidationForm />
    </Provider>,
    dest
  )
}

render()
```


# 実行結果

submitボタンをクリックしたときの画面です。

passwordエラー時の画面です。password field 個別のエラー 'Wrong password'が表示されています。加えてform全体のエラー 'Login failed!' が表示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61915/f29f3a84-36f8-93ed-5cb8-4617224da98a.png)


エラーなしで、成功時の画面です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61915/f579f397-559d-899f-1b14-80f76412d02a.png)



今回は以上です。