Comment obtenir la valeur d'un champ de saisie en utilisant ReactJS?

190

J'ai le composant React suivant:

export default class MyComponent extends React.Component {

    onSubmit(e) {
        e.preventDefault();
        var title = this.title;
        console.log(title);
    }

    render(){
        return (
            ...
            <form className="form-horizontal">
                ...
                <input type="text" className="form-control" ref={(c) => this.title = c} name="title" />
                ...
            </form>
            ...
            <button type="button" onClick={this.onSubmit} className="btn">Save</button>
            ...
        );
    }

};

La console me donne undefinedune idée de ce qui ne va pas avec ce code?

JoeTidee
la source
7
this.onSubmit.bind(this);
zerkms
Nice - je veux l'ajouter comme réponse et je vais le cocher (?)
JoeTidee
2
qu'en est-il e.target.valuesans la contrainte?
omarjmh
1
e.target.value ne ciblerait-il pas le bouton, pas le champ de saisie?
JoeTidee
Vous devez lier la onSubmitméthode au bouton d'envoi (élément DOM) lorsque vous cliquez dessus (c'est-à-dire onClick={this.onSubmit.bind(this)}). Et si vous souhaitez accéder à la valeur de l'entrée de titre dans le formulaire que vous pouvez utiliser onSubmit(event) { const title = event.target.elements.title.value; }.
tfmontague

Réponses:

11

Vous devez utiliser le constructeur sous la classe MyComponent extend React.Component

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

Ensuite, vous obtiendrez le résultat du titre

Md. Maidul Islam
la source
317

Il y a trois réponses ici, selon la version de React avec laquelle vous (êtes obligé) de travailler et si vous voulez utiliser des hooks.

Tout d'abord:

Il est important de comprendre comment réagissez des œuvres, afin que vous puissiez faire les choses correctement (protip: il est est super valeur en cours d' exécution à travers le React exercice tutoriel sur REACT site Il est bien écrit, et couvre toutes les bases d'une manière qui explique vraiment comment faire. des choses). «Correctement» signifie ici que vous écrivez une interface d'application qui se trouve être rendue dans un navigateur; tout le travail d'interface se produit dans React, pas dans "ce à quoi vous êtes habitué si vous écrivez une page Web" (c'est pourquoi les applications React sont des "applications", pas des "pages Web").

Les applications React sont rendues basées sur deux éléments:

  1. les propriétés du composant telles que déclarées par le parent qui crée une instance de ce composant, que le parent peut modifier tout au long de son cycle de vie, et
  2. le propre état interne du composant, qu'il peut modifier lui-même tout au long de son propre cycle de vie.

Ce que vous ne faites expressément pas lorsque vous utilisez React est de générer des éléments HTML, puis de les utiliser: lorsque vous dites à React d'utiliser un <input>, par exemple, vous ne créez pas d'élément d'entrée HTML, vous dites à React de créer un objet d'entrée React qui se produit pour être rendu en tant qu'élément d'entrée HTML, et dont la gestion des événements regarde, mais n'est pas contrôlée par , les événements d'entrée de l'élément HTML.

Lorsque vous utilisez React, vous générez des éléments d'interface utilisateur de l'application qui présentent à l'utilisateur des données (souvent manipulables), avec l'interaction de l'utilisateur modifiant l'état du composant, ce qui peut entraîner le rendu d'une partie de l'interface de votre application pour refléter le nouvel état. Dans ce modèle, l'état est toujours l'autorité finale, et non «quelle que soit la bibliothèque d'interface utilisateur utilisée pour le rendre», qui sur le Web est le DOM du navigateur. Le DOM est presque une réflexion après coup dans ce modèle de programmation: c'est juste le cadre d'interface utilisateur particulier que React utilise.

Donc, dans le cas d'un élément d'entrée, la logique est:

  1. Vous saisissez l'élément d'entrée,
  2. rien n'arrive encore à votre élément d'entrée, l'événement a été intercepté par React et tué immédiatement ,
  3. React transmet l'événement à la fonction que vous avez configurée pour la gestion des événements,
  4. cette fonction peut planifier une mise à jour de l'état,
  5. si c'est le cas, React exécute cette mise à jour d'état (de manière asynchrone!) et déclenchera un renderappel après la mise à jour, mais uniquement si la mise à jour d'état a changé l'état.
  6. seulement après que ce rendu a eu lieu, l'interface utilisateur montrera que vous avez "tapé une lettre".

Tout cela se produit en quelques millisecondes, sinon moins, il semble donc que vous ayez tapé dans l'élément d'entrée de la même manière que vous êtes habitué à "utiliser simplement un élément d'entrée sur une page", mais ce n'est absolument pas ce que arrivé.

Cela dit, comment obtenir des valeurs à partir d'éléments dans React:

React 15 et moins, avec ES5

Pour faire les choses correctement, votre composant a une valeur d'état, qui est affichée via un champ d'entrée, et nous pouvons la mettre à jour en faisant que cet élément de l'interface utilisateur renvoie les événements de modification dans le composant:

var Component = React.createClass({
  getInitialState: function() {
    return {
      inputValue: ''
    };
  },

  render: function() {
    return (
      //...
      <input value={this.state.inputValue} onChange={this.updateInputValue}/>
      //...
    );
  },

  updateInputValue: function(evt) {
    this.setState({
      inputValue: evt.target.value
    });
  }
});

Nous disons donc à React d'utiliser la updateInputValuefonction pour gérer l'interaction de l'utilisateur, de l'utiliser setStatepour planifier la mise à jour de l'état, et le fait que le fait de puiser renderdans this.state.inputValuesignifie que lorsqu'il réapparaît après la mise à jour de l'état, l'utilisateur verra le texte de mise à jour en fonction de ce qu'il a tapé.

addendum basé sur les commentaires

Étant donné que les entrées de l'interface utilisateur représentent des valeurs d'état (considérez ce qui se passe si un utilisateur ferme son onglet à mi-chemin et que l'onglet est restauré. Toutes les valeurs qu'il a renseignées doivent-elles être restaurées? Si tel est le cas, c'est l'état). Cela peut vous donner l'impression qu'un grand formulaire nécessite des dizaines, voire une centaine de formulaires de saisie, mais React consiste à modéliser votre interface utilisateur de manière maintenable: vous n'avez pas 100 champs de saisie indépendants, vous avez des groupes d'entrées associées, vous capturez donc chaque group dans un composant, puis construisez votre formulaire "maître" sous la forme d'un ensemble de groupes.

MyForm:
  render:
    <PersonalData/>
    <AppPreferences/>
    <ThirdParty/>
     ...

C'est également beaucoup plus facile à entretenir qu'un composant de formulaire unique géant. Divisez les groupes en composants avec maintenance de l'état, où chaque composant est uniquement responsable du suivi de quelques champs d'entrée à la fois.

Vous pouvez également avoir l'impression que c'est "un tracas" d'écrire tout ce code, mais c'est une fausse économie: les développeurs-qui-ne-sont-pas-vous, y compris le futur vous, bénéficient en fait grandement de voir toutes ces entrées connectées explicitement, car cela rend les chemins de code beaucoup plus faciles à tracer. Cependant, vous pouvez toujours optimiser. Par exemple, vous pouvez écrire un éditeur de liens d'état

MyComponent = React.createClass({
  getInitialState() {
    return {
      firstName: this.props.firstName || "",
      lastName: this.props.lastName || "" 
      ...: ...
      ...
    }
  },
  componentWillMount() {
    Object.keys(this.state).forEach(n => {
      let fn = n + 'Changed';
      this[fn] = evt => {
        let update = {};
        update[n] = evt.target.value;
        this.setState(update);
      });
    });
  },
  render: function() {
    return Object.keys(this.state).map(n => {
      <input
        key={n} 
        type="text"
        value={this.state[n]}
        onChange={this[n + 'Changed']}/>
    });
  }
});

Bien sûr, il existe des versions améliorées de ceci, alors rendez-vous sur https://npmjs.com et recherchez une solution de liaison d'état React que vous préférez. L'Open Source consiste principalement à trouver ce que les autres ont déjà fait et à l'utiliser au lieu de tout écrire vous-même à partir de zéro.

React 16 (et 15.5 transitionnel) et JS `` moderne ''

Depuis React 16 (et le démarrage progressif avec 15.5), l' createClassappel n'est plus pris en charge et la syntaxe de classe doit être utilisée. Cela change deux choses: la syntaxe de classe évidente, mais aussi la thisliaison de contexte qui createClasspeut faire "gratuitement", donc pour vous assurer que tout fonctionne toujours, assurez-vous que vous utilisez la notation "grosse flèche" pour thispréserver le contexte des fonctions anonymes dans les onWhatevergestionnaires, telles que le que onChangenous utilisons dans le code ici:

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

  render() {
    return (
      //...
      <input value={this.state.inputValue} onChange={evt => this.updateInputValue(evt)}/>
      //...
    );
  },

  updateInputValue(evt) {
    this.setState({
      inputValue: evt.target.value
    });
  }
});

Vous avez peut-être également vu des gens utiliser binddans leur constructeur pour toutes leurs fonctions de gestion d'événements, comme ceci:

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

render() {
  return (
    ...
    <element onclick={this.handler}/>
    ...
  );
}

Ne fais pas ça.

Presque chaque fois que vous l'utilisez bind, le proverbial «vous vous trompez» s'applique. Votre classe définit déjà le prototype d'objet et définit donc déjà le contexte de l'instance. Ne mettez pas bindde dessus; utilisez le transfert d'événement normal au lieu de dupliquer tous vos appels de fonction dans le constructeur, car cette duplication augmente votre surface de bogue et rend beaucoup plus difficile le suivi des erreurs car le problème peut être dans votre constructeur au lieu de l'endroit où vous appelez votre code. En plus d'imposer un fardeau de maintenance à d'autres personnes avec lesquelles vous (avez ou choisissez) de travailler.

Oui, je sais que les documents de réaction disent que ça va. Ce n'est pas, ne le fais pas.

React 16.8, en utilisant des composants de fonction avec des crochets

Depuis React 16.8, le composant de fonction (c'est-à-dire littéralement juste une fonction qui en prend propscomme argument peut être utilisée comme s'il s'agissait d'une instance d'une classe de composant, sans jamais écrire de classe) peut également recevoir un état, grâce à l'utilisation de hooks .

Si vous n'avez pas besoin d'un code de classe complet et qu'une seule fonction d'instance fera l'affaire, vous pouvez maintenant utiliser le useStatehook pour obtenir une seule variable d'état et sa fonction de mise à jour, qui fonctionne à peu près de la même manière que les exemples ci-dessus, sauf sans l' setStateappel de fonction:

import { useState } from 'react';

function myFunctionalComponentFunction() {
  const [input, setInput] = useState(''); // '' is the initial state value
  return (
    <div>
    <label>Please specify:</label>
    <input value={input} onInput={e => setInput(e.target.value)}/>
    </div>
  );
}

Auparavant, la distinction non officielle entre les classes et les composants de fonction était "les composants de fonction n'ont pas d'état", nous ne pouvons donc plus nous cacher derrière celui-là: la différence entre les composants de fonction et les composants de classes peut être trouvée répartie sur plusieurs pages dans le très bien -documentation de réaction écrite (pas de raccourci une explication de ligne pour mal interpréter pour vous!) que vous devriez lire afin que vous sachiez ce que vous faites et que vous puissiez ainsi savoir si vous avez choisi la meilleure solution (quoi que cela signifie pour vous) pour vous programmer d'un problème que vous rencontrez.

Mike 'Pomax' Kamermans
la source
4
J'ai lu quelques articles en ligne qui disent qu'utiliser trop d'état est une mauvaise idée. Dans un formulaire particulier de ma candidature, j'ai environ 100 champs de formulaire. Définir une fonction pour sauver l'état semble être une façon inutilement ardue de faire les choses. Si je peux utiliser onClick = {this.onSubmit.bind (this)}, cela semble être un bon moyen d'obtenir la valeur (alors si je veux, définissez l'état des composants) - j'apprécierais quelques commentaires à ce sujet.
JoeTidee
5
alors écrivez un code plus intelligent. les entrées de formulaire sont très certainement l'état (considérez ce qui se passe si un utilisateur ferme son onglet à mi-chemin et que l'onglet est restauré. Toutes les valeurs qu'ils ont remplies doivent-elles être restaurées? oui? c'est l'état ), alors écrivez un peu de code de maintenance d'état. Facebook a également des centaines de valeurs de forme, et leur solution à la folie était React. Cela fonctionne vraiment bien. Une façon de rendre votre code un peu plus facile, tout en utilisant l'état, est d'utiliser la liaison d'état bidirectionnelle , encore une fois, expliquée sur le site React. A lire! =)
Mike 'Pomax' Kamermans
2
Notez également que "100 champs" n'est généralement pas pertinent: divisez votre formulaire, car ce n'est pas 100 éléments, il s'agit de plusieurs sections, chacune avec un certain nombre d'entrées, alors appliquez une bonne conception et faites de chaque section son propre composant, avec des composants de regroupement pour le formulaire groupes. Cela rend généralement un composant responsable de moins de 10 entrées, et tout à coup, votre architecture d'informations prend beaucoup plus de sens. La soumission de formulaire, en tant qu'action du navigateur, voit bien sûr simplement "votre formulaire" et soumet tout en une seule fois. Conception d'interface utilisateur propre et ciblée.
Mike 'Pomax' Kamermans
2
Merci pour les commentaires. J'ai cependant remarqué que la liaison d'état était obsolète à partir de React v15.
JoeTidee
3
@JasonChing alors vous avez simplement intégré des bogues potentiels dans votre code. React n'est pas une solution "être tout, finissez tout" pour les pages Web, c'est un cadre pour la création d'interfaces, et il est responsable de la gestion de l'état et du rendu réel de l'interface utilisateur après coup (vos utilisateurs n'interagissent pas avec le DOM, ils interagissent avec Réagissez. Les mises à jour du DOM sont simplement une dernière étape asynchrone (mais incroyablement rapide) afin que l'interface utilisateur reflète visuellement l'état). Si vous voulez contourner cela, la question la plus importante est: pourquoi utilisez-vous React? Parce que le meilleur signe que vous l'utilisez mal est de combiner React et jQuery.
Mike 'Pomax' Kamermans
17

Géré pour obtenir la valeur du champ d'entrée en faisant quelque chose comme ceci:

import React, { Component } from 'react';

class App extends Component {

constructor(props){
super(props);

this.state = {
  username : ''
}

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


updateInput(event){
this.setState({username : event.target.value})
}


handleSubmit(){
console.log('Your input value is: ' + this.state.username)
//Send state to the server code
}



render(){
return (
    <div>
    <input type="text" onChange={this.updateInput}></input>
    <input type="submit" onClick={this.handleSubmit} ></input>
    </div>
  );
}
} 

//output
//Your input value is: x
Hugo Wesley
la source
1
Pourquoi utiliser "setState"? Cela implique un nouveau rendu ... n'est-ce pas?
Luca Davanzo
15

Dans react 16, j'utilise

<Input id="number" 
       type="time" 
       onChange={(evt) => { console.log(evt.target.value); }} />
Pyae Sone
la source
ne fonctionne pas si le champ a été renseigné automatiquement en fonction de l'âge
SeanMC
4

J'ai réussi à faire cela en liant le "this" à la fonction updateInputValue (evt) avec

this.updateInputValue = this.updateInputValue.bind (this);

Cependant, input value = {this.state.inputValue} ... s'est avéré être une mauvaise idée.

Voici le code complet dans babel ES6:

class InputField extends React.Component{


  constructor(props){
   super(props);
   //this.state={inputfield: "no value"};   
   this.handleClick = this.handleClick.bind(this);
   this.updateInputValue = this.updateInputValue.bind(this);
  }

  handleClick(){
   console.log("trying to add picture url");
   console.log("value of input field : "+this.state.inputfield);

  }

  updateInputValue(evt){
    //console.log("input field updated with "+evt.target.value);
    this.state={inputfield: evt.target.value};   

  }

  render(){
    var r; 
    r=<div><input type="text" id="addpixinputfield" 
            onChange={this.updateInputValue} />
      <input type="button" value="add" id="addpix" onClick={this.handleClick}/>
      </div>;    
    return r;
   }
}
Matthias Liszt
la source
2

votre erreur est due au fait que vous utilisez la classe et lorsque vous utilisez la classe, nous devons lier les fonctions avec This afin de bien fonctionner. de toute façon, il y a beaucoup de tutoriels sur les raisons pour lesquelles nous devrions «ceci» et ce que «ceci» fait en javascript.

si vous corrigez votre bouton d'envoi, cela devrait fonctionner:

<button type="button" onClick={this.onSubmit.bind(this)} className="btn">Save</button>

et aussi si vous souhaitez afficher la valeur de cette entrée dans la console, vous devez utiliser var title = this.title.value;

Soroush Bk
la source
2
ce lien pourrait être utile si vous voulez en savoir plus sur "ça"
Soroush Bk
2

Donnez <input>un identifiant unique

<input id='title' ...>

puis utilisez l' API Web standard pour la référencer dans le DOM

const title = document.getElementById('title').value

Pas besoin de mettre à jour continuellement l'état React à chaque pression de touche. Obtenez simplement la valeur lorsque cela est nécessaire.

Brent Washburne
la source
1
// On the state
constructor() {
  this.state = {
   email: ''
 }
}

// Input view ( always check if property is available in state {this.state.email ? this.state.email : ''}

<Input 
  value={this.state.email ? this.state.email : ''} 
  onChange={event => this.setState({ email: event.target.value)}
  type="text" 
  name="emailAddress" 
  placeholder="[email protected]" />
Kidali Kevin
la source
bien que votre réponse puisse être bonne pour la question, il est toujours préférable d'ajouter des explications. Veuillez prendre 2 minutes pour l'ajouter. Cela améliorera votre réponse également pour les futurs utilisateurs.
DaFois
bien sûr, je vais le faire.
Kidali Kevin
0

Vous pouvez obtenir une valeur d'entrée sans ajouter la fonction «onChange».

Ajoutez simplement à l'élément d'entrée un 'ref attr:

Et puis utilisez this.refs pour obtenir la valeur d'entrée lorsque vous en avez besoin.

E1ad
la source
3
Ce n'est plus recommandé.
JoeTidee
1
Vous pouvez les utiliser, mais il est recommandé de garder le flux de données dans une direction à l'aide d'accessoires et de rappels.
JoeTidee
Il serait bon d'ajouter un exemple d'ajout correct des références, c'est-à-dire en utilisant un rappel de référence au lieu d'une chaîne héritée.
JoeTidee
0

Changez votre référence en: ref='title'et supprimez name='title' Puis supprimez var title = this.titleet écrivez:

console.log(this.refs.title.value)

Vous devez également ajouter .bind(this)àthis.onSubmit

(Cela a fonctionné dans mon cas qui était assez similaire, mais à la place de onClickmoi onSubmit={...}, il a été mis en forme ( <form onSubmit={...} ></form>))

Katarzyna Wrońska
la source
0

si vous utilisez le composant de classe, alors seulement 3 étapes - vous devez d'abord déclarer l'état de votre entrée, par exemple this.state = {name: ''} . Deuxièmement, vous devez écrire une fonction pour définir l'état quand il change dans l'exemple ci-dessous, c'est setName () et enfin vous devez écrire l'entrée jsx par exemple <input value = {this.name} onChange = {this.setName} />

import React, { Component } from 'react'

export class InputComponents extends Component {
    constructor(props) {
        super(props)

        this.state = {
             name:'',
             agree:false
        }
        this.setName = this.setName.bind(this);
        this.setAgree=this.setAgree.bind(this);
    }

    setName(e){
        e.preventDefault();
        console.log(e.target.value);
        this.setState({
            name:e.target.value
        })
    }
    setAgree(){
        this.setState({
            agree: !this.state.agree
        }, function (){
            console.log(this.state.agree);
        })
    }
    render() {
        return (
            <div>
                <input type="checkbox" checked={this.state.agree} onChange={this.setAgree}></input>
                < input value={this.state.name} onChange = {this.setName}/>
            </div>
        )
    }
}

export default InputComponents
Seigneur
la source
0
export default class MyComponent extends React.Component {

onSubmit(e) {
    e.preventDefault();
    var title = this.title.value; //added .value
    console.log(title);
}

render(){
    return (
        ...
        <form className="form-horizontal">
            ...
            <input type="text" className="form-control" ref={input => this.title = input} name="title" />
            ...
        </form>
        ...
        <button type="button" onClick={this.onSubmit} className="btn">Save</button>
        ...
    );
}

};
Pranav Agarwal
la source
0

en utilisant des champs non contrôlés:

export default class MyComponent extends React.Component {

    onSubmit(e) {
        e.preventDefault();
        console.log(e.target.neededField.value);
    }

    render(){
        return (
            ...
            <form onSubmit={this.onSubmit} className="form-horizontal">
                ...
                <input type="text" name="neededField" className="form-control" ref={(c) => this.title = c} name="title" />
                ...
            </form>
            ...
            <button type="button" className="btn">Save</button>
            ...
        );
    }

};
Georg
la source