Redux-form handleSubmit: comment accéder à l'état du magasin?

Dans un redux-forme handleSubmit fonction, qui fait un appel Ajax, certaines propriétés de L'état Redux sont nécessaires dans L'Ajax (par exemple user ID).

Ce serait assez facile si je voulais définir handleSubmit dans la composante du formulaire: il suffit d'appeler mapStateToProps pour passer dans ce que j'ai besoin, et de le lire à partir de this.props dans mon handleSubmit.

cependant, comme un bon développeur React-Redux j'écris séparer de voir les composants et conteneurs, donc mon point de vue les composants peuvent être simples avec peu ou pas de comportement. Par conséquent, je veux définir handleSubmit dans mon conteneur.

encore une fois, simple - redux-form est mis en place pour faire cela. Définir un onSubmitmapDispatchToProps, et le formulaire d'appel automatiquement.

Sauf, oh, attendez,mapDispatchToProps il n'y a aucun moyen d'accéder à redux state.

Ok, pas de problème, je vais juste passer les accessoires dont j'ai besoin dans handleSubmit avec les valeurs d'un formulaire.

Hmm, attendez, il est impossible de passer n'importe quelles données dans handleSubmit en utilisant ce mécanisme! Vous obtenez un paramètre, values, et il n'y a pas moyen d'ajouter un autre paramètre.

ceci laisse les alternatives suivantes peu attrayantes (dont je peux vérifier que 1 et 2 fonctionnent):

1 définir un gestionnaire de soumission dans le composant form, et à partir de là, appeler ma propre fonction de gestionnaire de soumission personnalisée passée depuis mapDispatchToProps. Ce n'est pas grave, mais il faut que mon composant sache certains accessoires de l'état redux qui ne sont pas nécessaires pour afficher le formulaire. (Cette question n'est pas propre à redux-form.)

dumbSubmit(values)
{
  const { mySubmitHandler, user} = this.props;
  mySubmitHandler(values, user);
}

<form onSubmit={ handleSubmit(this.dumbSubmit.bind(this)) }>

Ou, de façon plus concise, ce peuvent être combinés en une flèche fonction:

<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props.user);}

alors pour rendre ce handler complètement agnostique, il pourrait passer tout cela.les étais de retour à la gestionnaire personnalisé:

<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props);}

2 Définir onSubmit dans mergeProps au lieu de mapDispatchToProps, il a donc accès à stateProps. Dan Abramov recommande de ne pas utiliser mergeProps (pour des raisons de performance), donc cela semble sous-optimal.

  function mergeProps(stateProps, dispatchProps, ownProps) {
  const { user } = stateProps.authReducer;
  const { dispatch } = dispatchProps;
  return {
    ...ownProps,
    ...dispatchProps,
    ...stateProps,
     onSubmit: (values) => {
       const { name, description } = values;
       const thing = new Thing(name, description, []);
       dispatch(createNewThing(thing, user.id));
     }
  }

3 copier les propriétés de l'état dans les champs redux-form qui ne sont pas associés à des contrôles d'entrée dans le composant form. Cela permettra d'assurer qu'ils sont accessibles dans le values paramètre passé à handleSubmit. Ça a l'air d'être une sorte de piratage.

il doit y avoir un meilleur moyen!

Est il y a une meilleure façon?

24
demandé sur stone 2016-05-31 10:35:30

3 réponses

après avoir passé du temps à peaufiner cette question, l'option #1 est en fait assez bonne, dans la dernière itération (fonction de flèche qui renvoie tous les accessoires au gestionnaire personnalisé). Elle permet au composant d'être apatride et complètement ignorant de tout état, qu'il ne mange pas. Donc je vais appeler ça une réponse raisonnable. J'aimerais entendre votre meilleure des solutions!


définir un gestionnaire de soumission à l'aide d'une fonction de flèche dans la composante de formulaire, et de là, appelez ma propre fonction de gestionnaire de soumission personnalisée passée depuis mapDispatchToProps.

<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props.user);}

alors pour rendre ce handler complètement agnostique, passez le tout.les étais de retour à la gestionnaire personnalisé:

<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props);}

si la fonction Submit n'a besoin que des valeurs et des accessoires qui ne faisaient pas partie de la forme, nous pouvons renvoyer seulement les accessoires que la forme n'utilise pas. Dans le cas d'une composante apatride, cela pourrait ressembler à:

const Thing_Create = ({ fields: {name, description}, 
    error, 
    handleSubmit, 
    mySubmitHandler, 
    submitting, 
    onCancel, 
    ...otherprops}) => {
return (
<div>
  <form onSubmit={ handleSubmit((values)=>{
    mySubmitHandler(values, otherprops);}) }>
[rest of form definition would go here]
12
répondu stone 2016-05-31 23:48:17

le meilleur moyen que j'ai trouvé est assez similaire à la première solution que vous avez trouvé.

profitez du fait que le handleSubmit prop passé par redux-forme peut prendre une fonction qui sera utilisée comme onSubmit prop, et utiliser l'application partielle passer tous les autres paramètres dont vous avez besoin onSubmit.

Action créateur:

function updateUser(id, { name, lastname }) { ... }

supposons que le composant obtienne un onUpdateUser propriété qui passe les paramètres directement au créateur de l'action. Et la composant obtient également user, un objet avec l' id propriété que nous voulons transmettre au créateur d'action avec les valeurs dans les champs.

Composant

<form onSubmit={this.props.handleSubmit(this.props.onUpdateUser.bind(null, this.props.user.id))}>

cela peut facilement être réécrit pour les composants fonctionnels apatrides, peut fonctionner pour n'importe quelle quantité de paramètres aussi longtemps que vous les placez sur la gauche dans le créateur d'action, et il n'a pas besoin de levage lourd, juste bind

2
répondu Marco Scabbiolo 2017-02-28 04:40:14

j'ai pu résoudre ce problème en liant this.

quelque part dans render()

<MyCustomFormComponent onSubmit={handleSubmit.bind(this)}/>

le handleSumit

  handleSubmit(fields) {
    this.props.onSubmit(fields); //this is properly bound, HURRAY :-)
  }

MapDispatchToPropspour les bons développeurs :-)

const mapDispatchToProps = dispatch => ({
  onSubmit: (fields) =>
    dispatch({type: auth.actionTypes.LOGIN, payload: auth.api.login(fields)})
});
1
répondu hhsadiq 2017-02-24 03:21:33