Obtenir des données de formulaire dans ReactJS


200

J'ai une forme simple dans ma renderfonction, comme ceci:

render : function() {
      return (
        <form>
          <input type="text" name="email" placeholder="Email" />
          <input type="password" name="password" placeholder="Password" />
          <button type="button" onClick={this.handleLogin}>Login</button>
        </form>
      );
    },
handleLogin: function() {
   //How to access email and password here ?
}

Que dois-je écrire dans mon handleLogin: function() { ... }accès Emailet mes Passwordchamps?


6
Remarque: vous devez gérer onSubmitle formulaire plutôt que le clic sur le bouton - de cette façon, vous gérerez également l'utilisateur soumettant le formulaire en appuyant sur Entrée.
developerbmw

11
Un <form>avec un <button>ou <input>avec type=submitsera envoyé lorsque l'utilisateur appuie sur Entrée dans l'un des formulaires <input type=text>. Si vous vous onClickappuyez sur un bouton, l'utilisateur doit cliquer sur le bouton ou le mettre au point et appuyer sur Entrée / Barre d'espace. L'utilisation onSubmitactivera les deux cas d'utilisation. Lorsque les formulaires ne prennent pas en charge Enter pour l'envoi, ils peuvent se sentir cassés.
Ross Allen

Réponses:


167

Utilisez les changeévénements sur les entrées pour mettre à jour l'état du composant et y accéder dans handleLogin:

handleEmailChange: function(e) {
   this.setState({email: e.target.value});
},
handlePasswordChange: function(e) {
   this.setState({password: e.target.value});
},
render : function() {
      return (
        <form>
          <input type="text" name="email" placeholder="Email" value={this.state.email} onChange={this.handleEmailChange} />
          <input type="password" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange}/>
          <button type="button" onClick={this.handleLogin}>Login</button>
        </form>);
},
handleLogin: function() {
    console.log("EMail: " + this.state.email);
    console.log("Password: " + this.state.password);
}

Violon de travail .

Aussi, lisez la documentation, il y a toute une section dédiée à la gestion des formulaires : Formulaires

Auparavant, vous pouviez également utiliser le mixeur d'assistance de liaison de données bidirectionnel de React pour obtenir la même chose, mais maintenant il est déconseillé de définir la valeur et de modifier le gestionnaire (comme ci-dessus):

var ExampleForm = React.createClass({
  mixins: [React.addons.LinkedStateMixin],
  getInitialState: function() {
    return {email: '', password: ''};
  },
  handleLogin: function() {
    console.log("EMail: " + this.state.email);
    console.log("Password: " + this.state.password);
  },
  render: function() {
    return (
      <form>
        <input type="text" valueLink={this.linkState('email')} />
        <input type="password" valueLink={this.linkState('password')} />
        <button type="button" onClick={this.handleLogin}>Login</button>
      </form>
    );
  }
});

La documentation est ici: Assistants de liaison bidirectionnelle .


3
Pour imiter correctement la fonctionnalité de valueLink, votre premier exemple doit définir les valueéléments d'entrée. Sans cela, les valeurs sont "incontrôlées" en termes de React. <input ... value={this.state.password}>.
Ross Allen

10
vous pouvez également utiliser un onSubmit avec le formulaire au lieu de onClick avec le bouton
sai

60
Pourquoi utiliser un état pour chaque élément du formulaire? Quelqu'un d'autre pense que c'est un mauvais schéma?
eveevans

6
Il semble que valueLink soit déconseillé
Matt Broekhuis

3
N'est-ce pas le stockage du mot de passe en texte clair côté client pour toujours? Cela ne semble pas vraiment approprié pour un champ de mot de passe.
NewbiZ

166

Il y a quelques façons de le faire:

1) Récupérer les valeurs d'un tableau d'éléments de formulaire par index

handleSubmit = (event) => {
  event.preventDefault();
  console.log(event.target[0].value)
}

2) Utilisation de l' attribut name en html

handleSubmit = (event) => {
  event.preventDefault();
  console.log(event.target.elements.username.value) // from elements property
  console.log(event.target.username.value)          // or directly
}

<input type="text" name="username"/>

3) Utilisation des références

handleSubmit = (event) => {
  console.log(this.inputNode.value)
}

<input type="text" name="username" ref={node => (this.inputNode = node)}/>

Exemple complet

class NameForm extends React.Component {
  handleSubmit = (event) => {
    event.preventDefault()
    console.log(event.target[0].value)
    console.log(event.target.elements.username.value)
    console.log(event.target.username.value)
    console.log(this.inputNode.value)
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input
            type="text"
            name="username"
            ref={node => (this.inputNode = node)}
          />
        </label>
        <button type="submit">Submit</button>
      </form>
    )
  }
}

1
Ceci est une réponse fantastique. Merci d'avoir énuméré plusieurs façons de procéder.
Beau Smith

L'option 2 ne fonctionne pas pour moi. Il n'y a pas de propriété "elements" ni "username", même si le nom de mon entrée est "username"
Madacol

@Madacol cela peut arriver si vous avez quelques entrées avec le même nom
Aliaksandr Sushkevich

45

Une autre approche consiste à utiliser l' refattribut et à référencer les valeurs avec this.refs. Voici un exemple simple:

render: function() {
    return (<form onSubmit={this.submitForm}>
        <input ref="theInput" />
    </form>);
},
submitForm: function(e) {
    e.preventDefault();
    alert(React.findDOMNode(this.refs.theInput).value);
}

Plus d'informations peuvent être trouvées dans les documents React: https://facebook.github.io/react/docs/more-about-refs.html#the-ref-string-attribute

Pour un grand nombre des raisons décrites dans Comment utiliser les boutons radio dans React? cette approche n'est pas toujours la meilleure, mais elle présente une alternative utile dans certains cas simples.


1
Cette solution est-elle vraiment meilleure et n'était-elle pas disponible à l'heure des questions, ou est-ce une méthode "laide"?
Wagner Leonardi

4
en fait, vous n'avez pas besoin de React.findDOMNode this.refs.theInput déjà un nœud html
Fareed Alnamrouti

23

Un moyen simple de gérer les arbitres:

class UserInfo extends React.Component {

  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(e) {
    e.preventDefault();
    
    const formData = {};
    for (const field in this.refs) {
      formData[field] = this.refs[field].value;
    }
    console.log('-->', formData);
  }

  render() {
    return (
        <div>
          <form onSubmit={this.handleSubmit}>
            <input ref="phone" className="phone" type='tel' name="phone"/>
            <input ref="email" className="email" type='tel' name="email"/>
            <input type="submit" value="Submit"/>
          </form>
        </div>
    );
  }
}

export default UserInfo;


2
Cette méthode sera un jour à l'avenir déconseillée. Les références ne doivent être utilisées qu'avec des rappels et non des chaînes. Pour plus de détails: facebook.github.io/react/docs/refs-and-the-dom.html
David Labbe

Cool! :) J'aime utiliser les Object.keys()suivis map()comme ceci:Object.keys(this.refs).map(field => formData[field] = this.refs[field].value)
Francis Rodrigues

Oui, les références de chaîne sont obsolètes. Une meilleure façon de le faire maintenant est d'utiliser le rappel onChange. Si vous voulez toujours utiliser des références, vous pouvez utiliser cette syntaxe:<input type="text" ref={(input) => { this.textInput = input; }} />
E. Fortes

I @ E.Fortes, pouvez-vous expliquer la méthode de rappel onChange? Merci beaucoup si vous voulez. Veuillez m'étiqueter afin que je sois informé de votre réponse.
Simona Adriani

un moyen simple serait (désolé le formateur de code ne fonctionne pas): la classe NameForm étend React.Component {constructor (props) {super (props); this.state = {value: ''}; this.handleChange = this.handleChange.bind (this); } handleChange (event) {this.setState ({value: event.target.value}); } render () {return (<form> <label> Nom: <input type = "text" value = {this.state.value} onChange = {this.handleChange} /> </label> </form>); }}
E. Fortes

23

Pour compléter la réponse de Michael Schock:

class MyForm extends React.Component {
  constructor() {
    super();
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(event) {
    event.preventDefault();
    const data = new FormData(event.target);

    console.log(data.get('email')); // reference by form input's `name` tag

    fetch('/api/form-submit-url', {
      method: 'POST',
      body: data,
    });
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label htmlFor="username">Enter username</label>
        <input id="username" name="username" type="text" />

        <label htmlFor="email">Enter your email</label>
        <input id="email" name="email" type="email" />

        <label htmlFor="birthdate">Enter your birth date</label>
        <input id="birthdate" name="birthdate" type="text" />

        <button>Send data!</button>
      </form>
    );
  }
}

Voir cet article moyen: Comment gérer les formulaires avec Just React

Cette méthode obtient les données du formulaire uniquement lorsque vous appuyez sur le bouton Soumettre. IMO beaucoup plus propre!


Réponse parfaite. 👌
Michal

16

Vous pouvez basculer le onClickgestionnaire d'événements du bouton sur un onSubmitgestionnaire du formulaire:

render : function() {
      return (
        <form onSubmit={this.handleLogin}>
          <input type="text" name="email" placeholder="Email" />
          <input type="password" name="password" placeholder="Password" />
          <button type="submit">Login</button>
        </form>
      );
    },

Ensuite, vous pouvez utiliser FormDatapour analyser le formulaire (et construire un objet JSON à partir de ses entrées si vous le souhaitez).

handleLogin: function(e) {
   const formData = new FormData(e.target)
   const user = {}

   e.preventDefault()

   for (let entry of formData.entries()) {
       user[entry[0]] = entry[1]
   }

   // Do what you will with the user object here
}

Exécuter ce plus 'console.log (utilisateur);' donne un objet sans valeur utilisable! Une opinion?
M au

@MahdiRafatjah ¯ \ _ (ツ) _ / ¯ - cela fonctionne dans ce violon: jsfiddle.net/mschock/exvko2Lf
Michael Schock

un de mes amis m'a référé pour réagir au document et ils le font comme ceci reactjs.org/docs/forms.html#controlled-components
M au

1
agréable, cela semble beaucoup plus propre =)
Michael Schock

13

Je suggérerais l'approche suivante:

import {Autobind} from 'es-decorators';

export class Form extends Component {

    @Autobind
    handleChange(e) {
        this.setState({[e.target.name]: e.target.value});
    }

    @Autobind
    add(e) {
        e.preventDefault();
        this.collection.add(this.state);
        this.refs.form.reset();
    }

    shouldComponentUpdate() {
        return false;
    }

    render() {
        return (
            <form onSubmit={this.add} ref="form">
                <input type="text" name="desination" onChange={this.handleChange}/>
                <input type="date" name="startDate" onChange={this.handleChange}/>
                <input type="date" name="endDate" onChange={this.handleChange}/>
                <textarea name="description" onChange={this.handleChange}/>
                <button type="submit">Add</button>
            </form>
        )
    }

}

Si vous ne restituez pas le composant, comment pouvez-vous définir la valeur de chaque élément en fonction de l'état actuel? par exemple "value = {this.state. destination}". De plus, vous ne pouvez pas exécuter les validations de réaction sur le formulaire si vous ne le restituez pas
Avishay28

13

Si toutes vos entrées / textarea ont un nom, vous pouvez filtrer tout depuis event.target:

onSubmit(event){
  const fields = Array.prototype.slice.call(event.target)
      .filter(el => el.name)
      .reduce((form, el) => ({
        ...form,
        [el.name]: el.value,
      }), {})
}

Forme totalement incontrôlée 😊 sans méthodes onChange, value, defaultValue ...


12

Pour ceux qui ne veulent pas utiliser ref et réinitialiser l'état avec OnChangeévénement, vous pouvez simplement utiliser une poignée OnSubmit simple et parcourir l' FormDataobjet. Cet exemple utilise React Hooks:

const LoginPage = () =>{
    const handleSubmit = (event) => {
        const formData = new FormData(event.target);
        event.preventDefault();
        for (var [key, value] of formData.entries()) {
            console.log(key, value);
        }
    }

    return (
        <div>
        <form onSubmit={
        handleSubmit
        }

        >
        <input type="text" name="username" placeholder="Email" />
        <input type="password" name="password"
        placeholder="Password" />
        <button type="submit">Login</button>
        </form>
        </div>)
        }

Excellente réponse, mais un nitpick pourrait vous enlever le var sinon la solution parfaite!
Louis345

5

En outre, cela peut également être utilisé.

handleChange: function(state,e) {
  this.setState({[state]: e.target.value});
},
render : function() {
  return (
    <form>
      <input type="text" name="email" placeholder="Email" value={this.state.email} onChange={this.handleChange.bind(this, 'email')} />
      <input type="password" name="password" placeholder="Password" value={this.state.password} onChange={this.handleChange.bind(this, 'password')}/>
      <button type="button" onClick={this.handleLogin}>Login</button>
    </form>
  );
},
handleLogin: function() {
  console.log("EMail: ", this.state.email);
  console.log("Password: ", this.state.password);
}

4
Veuillez expliquer pourquoi cette réponse est la bonne façon de procéder.
Tim Hutchison

1
J'utilise une seule méthode pour changer la forme du texte
Yurii Kosygin

Le mot de passe peut être vu dans les outils de développement de Rea, un problème de sécurité?
Neil

5

Donnez vos références ref comme ceci

<input type="text" name="email" placeholder="Email" ref="email" />
<input type="password" name="password" placeholder="Password" ref="password" />

alors vous pouvez y accéder dans votre poignée

handleLogin: function(e) {
   e.preventDefault();
    console.log(this.refs.email.value)
    console.log(this.refs.password.value)
}

5

Exemple plus clair avec la destruction d'es6

class Form extends Component {
    constructor(props) {
        super(props);
        this.state = {
            login: null,
            password: null,
            email: null
        }
    }

    onChange(e) {
        this.setState({
            [e.target.name]: e.target.value
        })
    }

    onSubmit(e) {
        e.preventDefault();
        let login = this.state.login;
        let password = this.state.password;
        // etc
    }

    render() {
        return (
            <form onSubmit={this.onSubmit.bind(this)}>
                <input type="text" name="login" onChange={this.onChange.bind(this)} />
                <input type="password" name="password" onChange={this.onChange.bind(this)} />
                <input type="email" name="email" onChange={this.onChange.bind(this)} />
                <button type="submit">Sign Up</button>
            </form>
        );
    }
}


4

Dans de nombreux événements en javascript, nous avons eventqui donnent un objet comprenant quel événement s'est passé et quelles sont les valeurs, etc ...

C'est ce que nous utilisons également avec les formulaires dans ReactJs ...

Donc, dans votre code, vous définissez l'état sur la nouvelle valeur ... quelque chose comme ceci:

class UserInfo extends React.Component {

  constructor(props) {
    super(props);
    this.handleLogin = this.handleLogin.bind(this);
  }

  handleLogin(e) {
    e.preventDefault();
    for (const field in this.refs) {
      this.setState({this.refs[field]: this.refs[field].value});
    }
  }

  render() {
    return (
        <div>
          <form onSubmit={this.handleLogin}>
            <input ref="email" type="text" name="email" placeholder="Email" />
            <input ref="password" type="password" name="password" placeholder="Password" />
            <button type="button">Login</button>
          </form>
        </div>
    );
  }
}

export default UserInfo;

Voici également l'exemple de formulaire dans React v.16, tout comme la référence pour le formulaire que vous créerez à l'avenir:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

4

J'utilise comme ceci en utilisant l'état du composant React:

<input type="text" name='value' value={this.state.value} onChange={(e) => this.handleChange(e)} />

handleChange(e){
   this.setState({[e.target.name]: e.target.value})
}`

3
 onChange(event){
     console.log(event.target.value);
  }
  handleSubmit(event){ 
    event.preventDefault();
    const formData = {};
      for (const data in this.refs) {
        formData[data] = this.refs[data].value;
      }
    console.log(formData);
  }



 <form onSubmit={this.handleSubmit.bind(this)}>
  <input type="text" ref="username" onChange={this.onChange} className="form-control"/>
  <input type="text" ref="password" onChange={this.onChange} className="form-control"/>
  <button type="submit" className="btn-danger btn-sm">Search</button>
 </form>

Image de sortie jointe ici


Veuillez également fournir une explication.
BlackBeard

2
Je vais essayer d'expliquer cela, que j'ai trouvé brillant. Dans la fonction handleSubmit (), vous créez un objet (formData) dans lequel la clé est l'attribut 'ref' de chaque entrée du formulaire (l'instruction 'formData [data]'), et la valeur est la valeur de l'entrée avec cet attribut 'ref' (l'instruction 'this.refs [data] .value'). Avec 'formData [data] = this.refs [data] .value', vous construisez cet objet. Vous dites, littéralement: formData ['username'] = (la valeur de l'entrée du nom d'utilisateur) et formData ['password'] = (la valeur de l'entrée du mot de passe) La sortie sera: {utilisateur: 'blablabla', mot de passe: 'xxx '}
Simona Adriani

Merci @SimonaAdriani pour votre explication.
Milan Panigrahi

2

Cela pourrait aider les utilisateurs de Meteor (v1.3):

render: function() {
    return (
        <form onSubmit={this.submitForm.bind(this)}>
            <input type="text" ref="email" placeholder="Email" />
            <input type="password" ref="password" placeholder="Password" />
            <button type="submit">Login</button>
        </form>
    );
},
submitForm: function(e) {
    e.preventDefault();
    console.log( this.refs.email.value );
    console.log( this.refs.password.value );
}

1
this.submitForm.bind (this) devrait être juste: this.submitForm
rekarnar

Erreur: les composants de fonction sans état ne peuvent pas avoir de références.
holms

Utilisez-vous Meteor (v1.3)?
Joe L.

1

Pour améliorer l'expérience utilisateur; lorsque l'utilisateur clique sur le bouton envoyer, vous pouvez essayer d'obtenir le formulaire pour afficher d'abord un message d'envoi. Une fois que nous avons reçu une réponse du serveur, il peut mettre à jour le message en conséquence. Nous y parvenons dans React en enchaînant les statuts. Voir codepen ou extraits ci-dessous:

La méthode suivante effectue le premier changement d'état:

handleSubmit(e) {
    e.preventDefault();
    this.setState({ message: 'Sending...' }, this.sendFormData);
}

Dès que React affiche le message d'envoi ci-dessus à l'écran, il appelle la méthode qui enverra les données du formulaire au serveur: this.sendFormData (). Pour plus de simplicité, j'ai ajouté un setTimeout pour imiter cela.

sendFormData() {
  var formData = {
      Title: this.refs.Title.value,
      Author: this.refs.Author.value,
      Genre: this.refs.Genre.value,
      YearReleased: this.refs.YearReleased.value};
  setTimeout(() => { 
    console.log(formData);
    this.setState({ message: 'data sent!' });
  }, 3000);
}

Dans React, la méthode this.setState () rend un composant avec de nouvelles propriétés. Vous pouvez donc également ajouter un peu de logique dans la méthode render () du composant de formulaire qui se comportera différemment selon le type de réponse que nous recevons du serveur. Par exemple:

render() {
  if (this.state.responseType) {
      var classString = 'alert alert-' + this.state.type;
      var status = <div id="status" className={classString} ref="status">
                     {this.state.message}
                   </div>;
  }
return ( ...

codepen


1

Si vous avez plusieurs occurrences d'un nom d'élément, vous devez utiliser forEach ().

html

  <input type="checkbox" name="delete" id="flizzit" />
  <input type="checkbox" name="delete" id="floo" />
  <input type="checkbox" name="delete" id="flum" />
  <input type="submit" value="Save"  onClick={evt => saveAction(evt)}></input>

js

const submitAction = (evt) => {
  evt.preventDefault();
  const dels = evt.target.parentElement.delete;
  const deleted = [];
  dels.forEach((d) => { if (d.checked) deleted.push(d.id); });
  window.alert(deleted.length);
};

Notez que le dels dans ce cas est un RadioNodeList, pas un tableau, et n'est pas un Iterable. ForEach () est une méthode intégrée de la classe list. Vous ne pourrez pas utiliser ici une carte () ou réduire ().

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.