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?

myusuf
la source
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 .

jbaiter
la source
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>
    )
  }
}
Aliaksandr Sushkevich
la source
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.

Jamund Ferguson
la source
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;

E. Fortes
la source
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!

hoohoo-b
la source
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
}
Michael Schock
la source
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>
        )
    }

}
James Akwuh
la source
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 ...

Aral Roca
la source
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>)
        }
CloudWave
la source
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);
}
Yurii Kosygin
la source
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)
}
Imran Rafique
la source
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>
        );
    }
}
Sergio Ivanuzzo
la source
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>
    );
  }
}
Alireza
la source
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})
}`
Adnan Boota
la source
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

Milan Panigrahi
la source
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 );
}
Joe L.
la source
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

Homam Bahrani
la source
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 ().

Jeff Lowery
la source