web-dev-qa-db-fra.com

Redux-form: afficher une liste d'erreurs en haut d'une page

Je veux utiliser Redux-form d'une manière qui change la couleur d'entrée et affiche l'erreur réelle en haut de la page. Comment accéder à la liste des erreurs de champ actuelles en dehors des champs eux-mêmes?

16
thevangelist

Vous ne pouvez pas obtenir la liste des erreurs en dehors de la fonction de rendu donnée au composant Field. En effet, les erreurs ne sont pas stockées dans le magasin redux.

EDIT 26/12/2018:

Cette réponse prend un certain temps. ReduxForm stocke désormais les erreurs dans le magasin Redux. Jetez un œil à @ réponse de nicoqh qui utilise les sélecteurs de ReduxForm pour obtenir des erreurs dans n'importe quel composant connecté à Redux.

Cette réponse n'est pas totalement obsolète mais ce n'est plus le moyen le plus propre de réaliser cet imho.

Solution 1: utiliser plusieurs champs pour la même valeur

La première solution consiste à utiliser plusieurs instances de Field pour la même valeur. Si plusieurs composants Field ont le même nom et sont connectés au même nom de formulaire, ils seront tous connectés à la même valeur et à la même gestion des erreurs.

Vous pouvez donc utiliser un composant Field et rendre uniquement l'erreur.

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)

Solution 2: utilisez l'accessoire d'erreur globale

Une deuxième solution consiste à utiliser les accessoires d'erreur globale, mais vous devrez afficher les erreurs du composant conteneur à l'aide de reduxForm.

Attention, c'est une totale antipaternité! L'erreur globale prop concerne les erreurs indépendantes du champ.

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)

Solution 3: obtenir des erreurs du magasin

Vous pouvez toujours obtenir des erreurs du magasin en appliquant votre fonction de validation sur la valeur présente dans le magasin. Il ne peut pas être performant pour une validation intensive car il passe par la validation à chaque rendu, il s'exécute donc deux fois lorsqu'une valeur change et un pour rien si d'autres accessoires changent. Cela peut également être difficile à faire avec la validation asynchrone.

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)

Une dernière solution peut être de stocker les erreurs dans le magasin en implémentant le componentWillReceiveProps et en envoyant une action pour mettre à jour une liste d'erreurs dans le magasin mais je ne pense pas que ce soit vraiment une bonne idée. Il est préférable de conserver un composant sans état simple pour rendre un composant Field.

EDIT 26/12/2018:

Cette dernière "solution" n'était pas bonne au moment où je l'ai publiée. Mais comme componentWillReceiveProps est déconseillé dans React, ce n'est pas du tout une solution. Veuillez ne pas le faire dans votre candidature. Je ne supprime pas cela pour l'historique au cas où cette réponse était liée quelque part.

20
Emrys Myrooin

Vous pouvez utiliser les sélecteurs d'état fournis par redux-form .

En particulier, getFormSubmitErrors vous donnera les erreurs de validation de soumission :

import { getFormSubmitErrors } from 'redux-form';

// ...

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

Le composant MyForm d'origine non connecté peut ressembler à ceci:

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

Si vous souhaitez afficher les erreurs de validation synchrone , vous pouvez utiliser le sélecteur getFormSyncErrors à la place.

13
nicoqh