web-dev-qa-db-fra.com

React.js: Identifier différentes entrées avec un seul gestionnaire onChange

Curieux de savoir quelle est la bonne façon de l'aborder:

var Hello = React.createClass({
getInitialState: function() {
    return {total: 0, input1:0, input2:0};
},
render: function() {
    return (
        <div>{this.state.total}<br/>
            <input type="text" value={this.state.input1} onChange={this.handleChange} />
            <input type="text" value={this.state.input2} onChange={this.handleChange} />
        </div>
    );
},
handleChange: function(e){
    this.setState({ ??? : e.target.value});
    t = this.state.input1 + this.state.input2;
    this.setState({total: t});
}
});

React.renderComponent(<Hello />, document.getElementById('content'));

Évidemment, vous pouvez créer des fonctions distinctes handleChange pour gérer chaque entrée différente, mais ce n'est pas très agréable. De même, vous pouvez créer un composant uniquement pour une entrée individuelle, mais je voulais voir s'il y avait un moyen de le faire comme ceci.

124
T3db0t

Je suggère de s'en tenir aux attributs HTML standard tels que name on input Elements pour identifier vos entrées. De plus, vous n'avez pas besoin de conserver "total" en tant que valeur distincte dans l'état, car il est possible de composer en ajoutant d'autres valeurs dans votre état:

var Hello = React.createClass({
    getInitialState: function() {
        return {input1: 0, input2: 0};
    },
    render: function() {
        const total = this.state.input1 + this.state.input2;

        return (
            <div>{total}<br/>
                <input type="text" value={this.state.input1} name="input1" onChange={this.handleChange} />
                <input type="text" value={this.state.input2} name="input2" onChange={this.handleChange} />
            </div>
        );
    },
    handleChange: function(e) {
        this.setState({[e.target.name]: e.target.value});
    }
});

React.renderComponent(<Hello />, document.getElementById('content'));
143
Ross Allen

Vous pouvez utiliser la méthode .bind pour pré-construire les paramètres de la méthode handleChange . Cela pourrait ressembler à ceci:

  var Hello = React.createClass({
    getInitialState: function() {
        return {input1:0, 
                input2:0};
    },
    render: function() {
      var total = this.state.input1 + this.state.input2;
      return (
        <div>{total}<br/>
          <input type="text" value={this.state.input1} 
                             onChange={this.handleChange.bind(this, 'input1')} />
          <input type="text" value={this.state.input2} 
                             onChange={this.handleChange.bind(this, 'input2')} />
        </div>
      );
    },
    handleChange: function (name, e) {
      var change = {};
      change[name] = e.target.value;
      this.setState(change);
    }
  });

  React.renderComponent(<Hello />, document.getElementById('content'));

(J'ai également fait calculer total au moment du rendu, comme il est recommandé de le faire.)

105
fiatjaf

Les bulles d'événement onChange ... Vous pouvez donc faire quelque chose comme ceci:

// A sample form
render () {
  <form onChange={setField}>
    <input name="input1" />
    <input name="input2" />
  </form>
}

Et votre méthode setField pourrait ressembler à ceci (si vous utilisez ES2015 ou une version ultérieure):

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

J'utilise quelque chose de similaire dans plusieurs applications, et c'est très pratique.

37
Christopher Davies

Solution obsolète

valueLink/checkedLink sont obsolète de Core React, car cela déroute certains utilisateurs. Cette réponse ne fonctionnera pas si vous utilisez une version récente de React. Mais si vous l'aimez, vous pouvez facilement l'imiter en créant votre propre composant Input

Ancien contenu de la réponse:

Ce que vous souhaitez réaliser peut être beaucoup plus facilement réalisé à l’aide des aides de liaison de données à deux voies de React.

var Hello = React.createClass({
    mixins: [React.addons.LinkedStateMixin],
    getInitialState: function() {
        return {input1: 0, input2: 0};
    },

    render: function() {
        var total = this.state.input1 + this.state.input2;
        return (
            <div>{total}<br/>
                <input type="text" valueLink={this.linkState('input1')} />;
                <input type="text" valueLink={this.linkState('input2')} />;
            </div>
        );
    }

});

React.renderComponent(<Hello />, document.getElementById('content'));

Facile non?

http://facebook.github.io/react/docs/two-way-binding-helpers.html

Vous pouvez même implémenter votre propre mixin

11
Sebastien Lorber

Vous pouvez aussi le faire comme ça: 

...
constructor() {
    super();
    this.state = { input1: 0, input2: 0 };
    this.handleChange = this.handleChange.bind(this);
}

handleChange(input, value) {
    this.setState({
        [input]: value
    })
}

render() {
    const total = this.state.input1 + this.state.input2;
    return (
        <div>
            {total}<br />
            <input type="text" onChange={e => this.handleChange('input1', e.target.value)} />
            <input type="text" onChange={e => this.handleChange('input2', e.target.value)} />
        </div>
    )
}
5
inostia

Vous pouvez utiliser un attribut React spécial appelé ref, puis faire correspondre les noeuds DOM réels dans l'événement onChange à l'aide de la fonction React's getDOMNode():

handleClick: function(event) {
  if (event.target === this.refs.prev.getDOMNode()) {
    ...
  }
}

render: function() {
  ...
  <button ref="prev" onClick={this.handleClick}>Previous question</button>
  <button ref="next" onClick={this.handleClick}>Next question</button>
  ...
}
4
Janusz Kacalak

@Vigril Disgr4ce

En ce qui concerne les formulaires multi-champs, il est logique d’utiliser la fonction clé de React: les composants.

Dans mes projets, je crée des composants TextField, qui prennent au minimum une propriété de valeur et qui s’occupe de la gestion des comportements courants d’un champ de texte de saisie. Ainsi, vous n'avez pas à vous soucier de garder une trace des noms de champs lors de la mise à jour de l'état de la valeur.

[...]

handleChange: function(event) {
  this.setState({value: event.target.value});
},
render: function() {
  var value = this.state.value;
  return <input type="text" value={value} onChange={this.handleChange} />;
}

[...]
0
manu3569

Vous pouvez suivre la valeur de chaque enfant input en créant un composant InputField distinct qui gère la valeur d'un seul input. Par exemple, la InputField pourrait être:

var InputField = React.createClass({
  getInitialState: function () {
    return({text: this.props.text})
  },
  onChangeHandler: function (event) {
     this.setState({text: event.target.value})
  }, 
  render: function () {
    return (<input onChange={this.onChangeHandler} value={this.state.text} />)
  }
})

La valeur de chaque input peut maintenant être suivie dans une instance distincte de ce composant InputField sans créer de valeurs distinctes dans l'état du parent pour surveiller chaque composant enfant.

0
Javasamurai