web-dev-qa-db-fra.com

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

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 undefined - des idées sur ce qui ne va pas avec ce code?

122
JoeTidee

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

Premières choses d'abord:

Il est important de comprendre le fonctionnement de React pour pouvoir faire les choses correctement (protip: c’est super ça vaut la peine de parcourir l’exercice didactique de React sur le site Web de React. C’est bien écrit et couvre toutes les bases manière qui explique réellement comment faire les choses). "Correctement" signifie ici que vous écrivez une interface d'application qui est rendue dans un navigateur; tout le travail d'interface s'effectue dans React et non dans "ce à quoi vous êtes habitué si vous écrivez une page Web" (c'est pourquoi les applications React sont des "applications" et non des "pages Web").

Les applications React sont rendues basées sur deux choses:

  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. l'état interne du composant, qu'il peut modifier tout au long de son cycle de vie.

Ce que vous faites expressément not ​​lorsque vous utilisez React, vous générez des éléments HTML que vous utilisez ensuite: lorsque vous indiquez à React d'utiliser un <input>, par exemple, vous créez not un élément d’entrée HTML, vous indiquez à React de créer un objet d’entrée React qui se produit comme render en tant qu’élément d’entrée HTML et dont la gestion des événements a pour aspect 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 de l'interface utilisateur de l'application qui présentent à l'utilisateur des données (souvent manipulables), l'interaction de l'utilisateur modifiant l'état du composant, ce qui peut ​​provoquer la restitution d'une partie de votre application. interface pour refléter le nouvel état. Dans ce modèle, l'état est always 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. Dans ce modèle de programmation, le modèle DOM est presque une réflexion après coup: il s’agit simplement du cadre d’interface utilisateur particulier utilisé par React.

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

  1. Vous tapez dans l'élément d'entrée,
  2. rien ne se passe encore pour votre élément d'entrée, l'événement a été intercepté par React et tué immédiatement ,
  3. Réagissez en transmettant l'événement à la fonction que vous avez configurée pour gérer l'événement,
  4. cette fonction peut ​​programmer une mise à jour d'état,
  5. si tel est le cas, React exécute cette mise à jour d'état (de manière asynchrone!) et déclenchera un appel renderaprès la mise à jour, mais seulement si la mise à jour de l'état modifié l'état.
  6. seulement après ce rendu aura lieu, l'interface utilisateur indiquera que vous avez "tapé une lettre".

Tout cela se produit en quelques millisecondes, sinon moins, de sorte que ressemble vous avez saisi dans l'élément d'entrée de la même manière que vous êtes habitué à "en utilisant simplement un élément d'entrée sur une page ", mais ce n'est absolument pas ce qui s'est passé.

Cela dit, comment obtenir les valeurs des éléments de React:

Réagissez à partir de 15 ans avec ES5

Pour faire les choses correctement, votre composant a une valeur d'état, qui est affichée via un champ de saisie. Nous pouvons la mettre à jour en faisant en sorte que cet élément d'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 demandons donc à React d'utiliser la fonction updateInputValuepour gérer l'interaction utilisateur, d'utiliser setStatepour planifier la mise à jour de l'état, et le fait que renderse connecte à this.state.inputValue signifie que lorsqu'il le restitue, l'utilisateur verra le texte de la mise à jour basé sur ce qu'ils ont tapé.

addendum basé sur des commentaires

Etant 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 au milieu, et l'onglet est restauré. Toutes les valeurs qu'ils ont renseignées doivent-elles être restaurées? Si c'est le cas, c'est l'état). Cela peut donner l’impression qu’une grande forme a besoin de dizaines, voire de cent formes d’entrée, mais React consiste à modéliser votre interface utilisateur de manière gérable: vous ne disposez pas de 100 champs d’entrée indépendants, vous avez des groupes d’entrées associées, vous devez donc les capturer. groupe dans un composant, puis construisez votre formulaire "maître" en tant que collection de groupes.

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

C’est aussi beaucoup plus facile à maintenir qu’un composant de forme unique géant. Divisez les groupes en composants avec maintenance d'état, chaque composant étant uniquement responsable du suivi de quelques champs d'entrée à la fois.

Vous pouvez également avoir l'impression qu'il est "fastidieux" d'écrire tout ce code, mais il s'agit d'une fausse sauvegarde: les développeurs-qui-ne-sont-pas-vous, y compris l'avenir, bénéficient grandement de voir toutes ces entrées connectées explicitement, car cela rend beaucoup plus facile le chemin des codes. 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 ce logiciel, alors lancez https://npmjs.com et recherchez une solution de liaison de l'état React que vous préférez. L'open source consiste principalement à trouver ce que d'autres ont déjà fait et à l'utiliser au lieu de tout écrire vous-même.

React 16 (et 15.5 de transition) et JS 'moderne'

À compter de React 16 (et commençant avec 15.5), l'appel createClassn'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 thisname__context que createClasspeut faire "gratuitement", afin de vous assurer que tout fonctionne toujours, assurez-vous d'utiliser la notation "fat arrow" pour thisen préservant les fonctions anonymes dans onWhateverhandlers. , comme le onChangeque nous 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 personnes 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 utilisez bindname__, le proverbial "vous ne le faites pas correctement" s'applique. Votre classe définit déjà le prototype et le modèle de programmation définit déjà le contexte de l'instance. Ne mettez pas bindof the top of qui utilise le transfert d'événements normal au lieu de dupliquer tous vos appels de fonction dans le constructeur. Maintenant que vous avez augmenté la surface de bogues et rendu beaucoup plus difficile le traçage des erreurs, le problème pourrait provenir de votre constructeur plutôt que de l'endroit où vous appelez votre code. En plus de placer un fardeau de maintenance sur les autres avec lesquels vous (avez ou choisissez) de travailler.

Oui, je sais que les médecins 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

A partir de React 16.8, le composant function (c’est-à-dire qu’une fonction prenant simplement un argument propspeut être utilisé comme s’il s’agissait d’une instance d’une classe de composant, sans jamais écrire de classe) peut également être attribué à un état, à l’aide de - crochets .

Si vous n'avez pas besoin du code de classe complet et qu'une fonction d'instance unique suffira, vous pouvez maintenant utiliser le crochet useStatepour obtenir une seule variable d'état et sa fonction de mise à jour, qui fonctionne à peu près comme les exemples ci-dessus, à l'exception de sans l'appel de fonction setStatename__:

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 officieuse 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-ci: la différence entre les composants de fonction et les composants de classe peut être trouvée répartie sur plusieurs pages dans le même fichier -written réaction documentation (aucune explication de type raccourci pour mal interpréter pour vous!) que vous devriez lire pour savoir ce que vous faites et savoir si vous avez choisi le meilleur (peu importe ce que cela signifie pour vous) solution pour vous programmer hors d'un problème que vous rencontrez.

186

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
12
Hugo Wesley

En réaction 16, j'utilise

<Input id="number" 
       type="time" 
       onChange={(evt) => { console.log(evt.target.value); }} />
8
Pyae Sone

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

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

Cependant, la valeur d'entrée = {this.state.inputValue} ... ne s'est pas avérée être une bonne 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;
   }
}
3
Matthias Liszt

votre erreur est due à l'utilisation de 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 la raison pour laquelle nous devrions "ceci" et ce que "cela" fait en javascript.

si vous corrigez votre bouton d'envoi, cela devrait être un travail:

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

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

2
Soroush Bk

Vous pouvez obtenir une valeur d'entrée sans ajouter de fonction 'onChange'.

Il suffit d'ajouter à l'élément d'entrée un 'ref attr:

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

0
E1ad

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

0
Md. Maidul Islam