web-dev-qa-db-ja.com

Redux-form:ページの上部にエラーのリストを表示します

入力色を変更し、ページの上部に実際のエラーを表示する方法でReduxフォームを使用したいと思います。現在のフィールドエラーのリストにフィールド自体の外でアクセスするにはどうすればよいですか?

16
thevangelist

Fieldコンポーネントに与えられたレンダリング関数の外部からエラーのリストを取得することはできません。これは、エラーがreduxストアに格納されないためです。

編集26/12/2018:

この答えは少し時間がかかります。 ReduxFormは、エラーをReduxストアに格納するようになりました。 @ nicoqhの回答 を見てください。これは、ReduxFormのセレクターを使用して、Reduxに接続されたコンポーネントでエラーを取得しています。

この答えは完全に古くなっているわけではありませんが、この無差別を達成するための最もクリーンな方法ではありません。

解決策1:同じ値に複数のフィールドを使用する

最初の解決策は、同じ値に対してFieldの複数のインスタンスを使用することです。複数のFieldコンポーネントが同じ名前を持ち、同じフォーム名に接続されている場合、それらはすべて同じ値と同じエラー処理に接続されます。

したがって、Fieldコンポーネントを使用して、エラーのみをレンダリングできます。

import React from 'react'
import {reduxForm} from 'redux-form'

const renderError = ({input, meta, ...props}) => (
    <span {...props} className='error'>Error : {meta.error}</span>
)

const renderInput = ({input, meta, ...props}) => (
    <input {...input} {...props} className={meta.error ? 'error' : null} />
)

const FormWithError = ({handleSubmit}) => (
    <div>
        <div className='errorContainer'>
            <Field name='myInput' component={renderError} />
        </div>
        <form onSubmit={handleSubmit}>
            <Field name='myInput' component={renderInput} />
        </form>
    </div>
)

const validate = (values, props) => {
    const errors = {}
    /* calculate errors here by appending theim to errors object */
    return errors
}

export default reduxForm({form: 'myForm', validate})(FormWithError)

解決策2:グローバルエラープロパティを使用する

2番目の解決策は、グローバルエラープロパティを使用することですが、reduxFormを使用してコンテナーコンポーネントからのエラーを表示する必要があります。

これは完全なアンチパターンであることに注意してください!グローバルエラープロパティは、フィールドに依存しないエラー用です。

import React from 'react'
import {reduxForm} from 'redux-form'

const renderInput = ({input, meta, ...props}) => (
    <input {...input} {...props} className={meta.error ? 'error' : null} />
)

const FormWithError = ({handleSubmit, error}) => (
    <div>
        <div className='errorContainer'>
            <span {...props} className='error'>Error : {error}</span>
        </div>
        <form onSubmit={handleSubmit}>
            <Field name='myInput' component={renderInput} />
        </form>
    </div>
)

const validate = (values, props) => {
    const errors = {}
    /* calculate errors here by appending theim to errors object */
    if(Object.keys(errors) > 0) {
        //You can concatenate each error in a string
        for(key in errors) errors._error += key + ': ' + errors[key]
        //or juste put the errors object in the global error property
        errors._error = {...errors}
    }
    return errors
}

export default reduxForm({form: 'myForm', validate})(FormWithError)

解決策3:ストアからエラーを取得する

ストアに存在する値に検証関数を適用することで、常にストアからエラーを取得できます。レンダリングごとに検証を実行するため、厳密な検証ではパフォーマンスが低下する可能性があります。したがって、値が変更されると2回実行され、他のプロパティが変更されると1回実行されます。また、非同期検証を行うのが難しい場合もあります。

import React from 'react'
import {reduxForm, formValueSelector} from 'redux-form'
import {connect} from 'redux'

const renderErrors = errors => {
    const errorNodes = []
    for(key in errors) errorNodes.Push(<span className='error'>{key}: {errors[key]}</span>)
    return errorNodes
}

const renderInput = ({input, meta, ...props}) => (
    <input {...input} {...props} className={meta.error ? 'error' : null} />
)

let FormWithError = ({handleSubmit, values, ...otherProps}) => (
    <div>
        <div className='errorContainer'>
            {renderErrors(validate(values, otherProps))}
        </div>
        <form onSubmit={handleSubmit}>
            <Field name='myInput1' component={renderInput} />
            <Field name='myInput2' component={renderInput} />
        </form>
    </div>
)

const validate = (values, props) => {
    const errors = {}
    /* calculate errors here by appending theim to errors object */
    return errors
}

FormWithError = reduxForm({form: 'myForm', validate})(FormWithError)
FormWithError = connect(
    state => formValueSelector('myForm')(state, 'myInput1', 'myInput2')
)(FormWithError)

最後の解決策は、componentWillReceivePropsを実装し、ストア内のエラーのリストを更新するアクションをディスパッチすることにより、ストアにエラーを格納することですが、それは本当に良い考えではないと思います。 Fieldコンポーネントをレンダリングするには、単純なステートレスコンポーネントを保持することをお勧めします。

編集26/12/2018:

この最後の「解決策」は、私が投稿した時点では適切ではありませんでした。しかし、componentWillReceivePropsはReactではdeprecatedなので、まったく解決策ではありません。アプリケーションではこれを行わないでください。この回答がどこかにリンクされている場合に備えて、履歴からこれを削除しません。

20
Emrys Myrooin

redux-formが提供する状態セレクター を使用できます。

特に、getFormSubmitErrorsは、送信検証エラーを提供します:

import { getFormSubmitErrors } from 'redux-form';

// ...

const MyFormWithErrors = connect(state => ({
  submitErrors: getFormSubmitErrors('my-form')(state)
}))(MyForm);

元の未接続のMyFormコンポーネントは次のようになります。

const MyForm = reduxForm({
  form: 'my-form',
})(ManageUserProfile);

同期検証エラーを表示したい場合は、代わりにgetFormSyncErrorsセレクターを使用できます。

13
nicoqh