React.js: Identifizieren verschiedener Eingaben mit einem onChange-Handler

141

Neugierig, wie man das richtig angeht:

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'));

Natürlich könnten Sie separate handleChange-Funktionen erstellen, um jede unterschiedliche Eingabe zu verarbeiten, aber das ist nicht sehr schön. Ebenso könnten Sie eine Komponente nur für eine einzelne Eingabe erstellen, aber ich wollte sehen, ob es eine Möglichkeit gibt, dies so zu tun.

T3db0t
quelle

Antworten:

162

Ich empfehle, sich an Standard-HTML-Attribute wie namebei inputElements zu halten, um Ihre Eingaben zu identifizieren. Außerdem müssen Sie "total" nicht als separaten Wert im Status beibehalten, da es durch Hinzufügen anderer Werte in Ihrem Status zusammengesetzt werden kann:

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'));
Ross Allen
quelle
3
Ich habe anfangs versucht, dies zu tun, aber setState ({e.target.name ... funktioniert nicht - es ist ein Syntaxfehler. Sie müssen ein temporäres Objekt mit obj [e.target.name] erstellen und setState darauf setzen. Diese Art von funktioniert, aber es scheint eine Art Verzögerung bei der Aktualisierung des
Statusobjekts zu geben
1
Die "Art der Verzögerung" ist setState-Aktualisierung während requestAnimationFrame (ich nehme an), also ignorieren Sie diese Bemerkung
T3db0t
24
@ T3db0t Diese ES6-Syntax funktioniert:this.setState({ [e.target.name]: e.target.value });
XåpplI'-I0llwlg'I -
2
Die Verwendung von bind ist der bessere Ansatz. Dieser Ansatz funktioniert nicht, wenn Sie den onChange-Handler an ein Element ohne Namenseigenschaft anhängen, z. B. ein div.
Ericgrosse
3
@ericgrosse bind ist in diesem Fall nicht besser, da Sie viele unnötige Funktionen erstellen. Sie können bei Bedarf auch ein Datenattribut oder etwas anderes für eine andere Art von Element verwenden
aw04
106

Mit der .bindMethode können Sie die Parameter für die handleChangeMethode vorab erstellen . Es wäre so etwas wie:

  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'));

(Ich habe auch totaldafür gesorgt, dass es beim Rendern berechnet wird, da dies die empfohlene Vorgehensweise ist.)

Fiatjaf
quelle
13
Nur eine kurze Erinnerung, this.handleChange.bind(...)die eine neue Funktion erstellt. Wenn Sie shouldComponentUpdatemit PureRenderMixinoder etwas Ähnlichem verwenden, wird es kaputt gehen. Alle Ihre Eingabekomponenten werden erneut gerendert, wenn sich ein einzelner Wert ändert.
Zemirco
5
Wenn Sie die Implementierung von handleChangein ändern , können handleChange(name) { return event => this.setState({name: event.target.value}); }Sie die "gleiche" Funktion übergeben (es wird keine neue Funktion erstellt, wie dies mit verwendet wird.bind() Dann" möglich ist. Sie können die folgende Funktion übergeben:this.handleChange("input1")
Andreyco,
1
Ich denke, es ist auch wichtig zu erwähnen, dass die Natur von setState darin besteht, dass man nicht in der Lage ist, den aktuellen Status in der handChange-Funktion abzurufen, sondern den vorherigen Status, beispielsweise mit this.state.input1. Ein geeigneter Ansatz besteht darin, einen Rückruf wie die folgende zu erstellen this.setState(change, function () { console.log(this.state.input1); );: stackoverflow.com/questions/30782948/…
Charlie-Greenman
38

Das onChangeEreignis sprudelt ... Sie können also so etwas tun:

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

Und Ihre setField-Methode könnte folgendermaßen aussehen (vorausgesetzt, Sie verwenden ES2015 oder höher:

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

Ich verwende etwas Ähnliches in mehreren Apps und es ist ziemlich praktisch.

Christopher Davies
quelle
11

Veraltete Lösung

valueLink/checkedLinksind veraltet von Core React , da dies einige Benutzer verwirrt. Diese Antwort funktioniert nicht, wenn Sie eine aktuelle Version von React verwenden. Aber wenn es Ihnen gefällt, können Sie es einfach emulieren, indem Sie Ihr eigenes erstellenInput Komponente

Alter Antwortinhalt:

Was Sie erreichen möchten, können mit den 2-Wege-Datenbindungshilfen von React viel einfacher erreicht werden.

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'));

Einfach richtig?

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

Sie können sogar Ihr eigenes Mixin implementieren

Sebastien Lorber
quelle
Warum müssen wir einen Wechsel binden, um den Status festzulegen? Es ist immerhin ReactJS!
Junaid Qadir
Beachten Sie, dass diese Lösung veraltet ist
Philipp
6

Sie können es auch so machen:

...
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>
    )
}
Inostia
quelle
hat bei mir nicht funktioniert. sah React Entwickler-Tools. Das Erstellen und Zuweisen von Werten zu Variablen / Objekten, die als Eingabe bezeichnet werden, anstelle von Eingabe1 / Eingabe2
Gaurravs
1
@ Gaurravs ja du hast recht. Ich brauchte hinzufügen []um inputin setState. Das macht die Eigenschaft dynamisch zugewiesen
Inostia
4

Sie können ein spezielles ReactAttribut verwenden, das aufgerufen wird, refund dann die realen DOM-Knoten im onChangeEreignis mit Reactder folgenden getDOMNode()Funktion abgleichen:

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>
  ...
}
Janusz Kacalak
quelle
Zumindest in 0.13 hat this.refs keine Eigenschaft pref.
Blub
2
@usagidon - previst nur ein Name, den ich in der render()Methode festgelegt habe
Janusz Kacalak
2
Ab React v0.14 können Sie dies einfach tun event.target === this.refs.prev. facebook.github.io/react/blog/2015/10/07/…
XåpplI'-I0llwlg'I -
0

@ Vigril Disgr4ce

Wenn es um Formulare mit mehreren Feldern geht, ist es sinnvoll, die Hauptfunktion von React zu verwenden: Komponenten.

In meinen Projekten erstelle ich TextField-Komponenten, die mindestens eine Wertstütze benötigen, und kümmert sich um das allgemeine Verhalten eines Eingabetextfelds. Auf diese Weise müssen Sie sich beim Aktualisieren des Wertstatus nicht darum kümmern, die Feldnamen im Auge zu behalten.

[...]

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} />;
}

[...]
manu3569
quelle
0

Sie können den Wert jedes untergeordneten inputElements verfolgen, indem Sie eine separate InputFieldKomponente erstellen , die den Wert einer einzelnen Komponente verwaltet input. Zum Beispiel InputFieldkönnte das sein:

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} />)
  }
})

Jetzt kann der Wert jeder Komponente inputin einer separaten Instanz dieser InputFieldKomponente verfolgt werden, ohne dass im übergeordneten Status separate Werte erstellt werden müssen, um jede untergeordnete Komponente zu überwachen.

Javasamurai
quelle
0

Ich werde eine wirklich einfache Lösung für das Problem anbieten. Angenommen, wir haben zwei Eingänge usernameundpassword , aber wir möchten, dass unser Handle einfach und allgemein ist, damit wir es wiederverwenden und keinen Boilerplate-Code schreiben können.

I.Unsere Form:

                <form>
                    <input type="text" name = "username" onChange={this.onChange} value={this.state.username}/>
                    <input type="text" name = "password" onChange={this.onChange} value={this.state.password}/>
                    <br></br>
                    <button type="submit">Submit</button>
                </form>

II.Our Konstruktor, die wir sparen wollen usernameund password, damit wir sie leicht zugänglich machen können:

constructor(props) {
    super(props);
    this.state = {
        username: '',
        password: ''
    };

    this.onSubmit = this.onSubmit.bind(this);
    this.onChange = this.onChange.bind(this);
}

III. Das interessante und "generische" Handle mit nur einem onChangeEreignis basiert darauf:

onChange(event) {
    let inputName = event.target.name;
    let value = event.target.value;

    this.setState({[inputName]:value});


    event.preventDefault();
}

Lassen Sie mich erklären:

1.Wenn eine Änderung erkannt onChange(event)wird, wird die aufgerufen

2. Dann erhalten wir den Namensparameter des Feldes und seinen Wert:

let inputName = event.target.name; ex: username

let value = event.target.value; ex: itsgosho

3. Basierend auf dem Parameter name erhalten wir unseren Wert aus dem Status im Konstruktor und aktualisieren ihn mit dem Wert:

this.state['username'] = 'itsgosho'

4.Der hier zu beachtende Schlüssel ist, dass der Name des Feldes mit unserem Parameter im Status übereinstimmen muss

Hoffe ich habe jemandem irgendwie geholfen :)

Georgi Peev
quelle
0

Der Schlüssel Ihres Staates sollte mit dem Namen Ihres Eingabefeldes übereinstimmen. Dann können Sie dies in der handleEvent-Methode tun;

this.setState({
        [event.target.name]: event.target.value
});
Rajan
quelle
-1

Hallo habe ssorallen Antwort verbessert . Sie müssen die Funktion nicht binden, da Sie ohne sie auf die Eingabe zugreifen können.

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

React.renderComponent(<Hello />, document.getElementById('content'));
Albert Olivé
quelle