Ich habe eine Komponente, die ein Kontaktobjekt als Status speichert - {firstName: "John", lastName: "Doe", phone: "1234567890} Ich möchte ein Formular erstellen, um dieses Objekt zu bearbeiten, aber wenn die Eingaben den Wert enthalten sollen Für den ursprünglichen Kontaktparameter muss ich jeden Eingang zu einer kontrollierten Komponente machen, jedoch weiß ich nicht, wie ich eine handleChange-Funktion erstellen kann, die sich an jeden Parameter anpasst, da mein Status nur {contact: {...}} enthält. Unten ist was ich momentan habe -
getInitialState: function () {
return ({contact: {}});
},
handleChange: function (event) {
this.setState({contact: event.target.value });
},
render: function () {
return (
<div>
<input type="text" onChange={this.handleChange} value={this.state.contact.firstName}/>
<input type="text" onChange={this.handleChange} value={this.state.contact.lastName}/>
<input type="text" onChange={this.handleChange} value={this.state.contact.lastName}/>
</div>
);
}
Ich wünschte, in meinem Griff kann ich so etwas machen
handleChange: function (event) {
this.setState({contact.firstName: event.target.value });
}
Es gibt einen "einfachen" Weg, dies zu tun, und einen "intelligenten" Weg. Wenn Sie mich fragen, ist es nicht immer der beste Weg, Dinge auf intelligente Weise zu tun, da ich später vielleicht schwieriger damit arbeiten kann. In diesem Fall sind beide durchaus verständlich.
Randbemerkung: Eine Sache, über die ich nachdenken sollte, ist, müssen Sie das contact
-Objekt aktualisieren, oder können Sie firstName
direkt auf dem Status belassen? Möglicherweise haben Sie viele Daten im Status der Komponente? Wenn dies der Fall ist, ist es wahrscheinlich eine gute Idee, sie in kleinere Komponenten mit engeren Verantwortlichkeiten aufzuteilen.
changeFirstName: function (event) {
const contact = this.state.contact;
contact.firstName = event.target.value;
this.setState({ contact: contact });
},
changeLastName: function (event) {
const contact = this.state.contact;
contact.lastName = event.target.value;
this.setState({ contact: contact });
},
changePhone: function (event) {
const contact = this.state.contact;
contact.phone = event.target.value;
this.setState({ contact: contact });
},
render: function () {
return (
<div>
<input type="text" onChange={this.changeFirstName.bind(this)} value={this.state.contact.firstName}/>
<input type="text" onChange={this.changeLastName.bind(this)} value={this.state.contact.lastName}/>
<input type="text" onChange={this.changePhone.bind(this)} value={this.state.contact.phone}/>
</div>
);
}
handleChange: function (propertyName, event) {
const contact = this.state.contact;
contact[propertyName] = event.target.value;
this.setState({ contact: contact });
},
render: function () {
return (
<div>
<input type="text" onChange={this.handleChange.bind(this, 'firstName')} value={this.state.contact.firstName}/>
<input type="text" onChange={this.handleChange.bind(this, 'lastName')} value={this.state.contact.lastName}/>
<input type="text" onChange={this.handleChange.bind(this, 'phone')} value={this.state.contact.lastName}/>
</div>
);
}
Dieser Abschnitt enthält die gleichen Beispiele wie oben gezeigt, verwendet jedoch Funktionen von ES2015 +.
Um die folgenden Funktionen über Browser hinweg zu unterstützen, müssen Sie Ihren Code mit Babel mit den Voreinstellungen es2015 und reag , Und dem Plugin transpilieren Stufe 0 .
Nachfolgend finden Sie aktualisierte Beispiele. Verwenden Sie Objektzerstrukturierung , um den Kontakt aus dem Status Spread-Operator in Abzurufen. Erstellen Sie ein aktualisiertes Kontaktobjekt, anstatt das vorhandene zu mutieren Erstellen von Komponenten als Klassen um Erweitern von React.Component , und Verwenden von Pfeil-Funktionen , um Callbacks zu erstellen. t muss bind(this)
.
class ContactEdit extends React.Component {
changeFirstName = (event) => {
const { contact } = this.state;
const newContact = {
...contact,
firstName: event.target.value
};
this.setState({ contact: newContact });
}
changeLastName = (event) => {
const { contact } = this.state;
const newContact = {
...contact,
lastName: event.target.value
};
this.setState({ contact: newContact });
}
changePhone = (event) => {
const { contact } = this.state;
const newContact = {
...contact,
phone: event.target.value
};
this.setState({ contact: newContact });
}
render() {
return (
<div>
<input type="text" onChange={this.changeFirstName} value={this.state.contact.firstName}/>
<input type="text" onChange={this.changeLastName} value={this.state.contact.lastName}/>
<input type="text" onChange={this.changePhone} value={this.state.contact.phone}/>
</div>
);
}
}
Beachten Sie, dass handleChangeFor
eine curried-Funktion : .__ ist. Wenn Sie sie mit einer propertyName
aufrufen, wird eine Rückruffunktion erstellt, die beim Aufruf [propertyName]
des Kontaktobjekts (New) im Status aktualisiert.
class ContactEdit extends React.Component {
handleChangeFor = (propertyName) => (event) => {
const { contact } = this.state;
const newContact = {
...contact,
[propertyName]: event.target.value
};
this.setState({ contact: newContact });
}
render() {
return (
<div>
<input type="text" onChange={this.handleChangeFor('firstName')} value={this.state.contact.firstName}/>
<input type="text" onChange={this.handleChangeFor('lastName')} value={this.state.contact.lastName}/>
<input type="text" onChange={this.handleChangeFor('phone')} value={this.state.contact.lastName}/>
</div>
);
}
}
ES6 Ein-Liner-Ansatz
<input type="text"
value={this.state.username}
onChange={(e) => this.setState({ username: e.target.value })}
id="username"/>
Es gibt zwei Möglichkeiten, den Status eines verschachtelten Objekts zu aktualisieren:
Wie das funktioniert, erfahren Sie in JS Fiddle . Der Code ist auch unten:
var Component = React.createClass({
getInitialState: function () {
return ({contact: {firstName: "first", lastName: "last", phone: "1244125"}});
},
handleChange: function (key,event) {
console.log(key,event.target.value);
//way 1
//var updatedContact = JSON.parse(JSON.stringify(this.state.contact));
//updatedContact[key] = event.target.value;
//way 2 (Recommended)
var updatedContact = React.addons.update(this.state.contact, {
[key] : {$set: event.target.value}
});
this.setState({contact: updatedContact});
},
render: function () {
return (
<div>
<input type="text" onChange={this.handleChange.bind(this,"firstName")} value={this.state.contact.firstName}/>
<input type="text" onChange={this.handleChange.bind(this,"lastName")} value={this.state.contact.lastName}/>
<input type="text" onChange={this.handleChange.bind(this,"phone")} value={this.state.contact.phone}/>
</div>
);
}
});
ReactDOM.render(
<Component />,
document.getElementById('container')
);
Hier ist eine generische;
handleChange = (input) => (event) => {
this.setState({
...this.state,
[input]: event.target.value
});
}
Und so verwenden;
<input handleChange ={this.handleChange("phone")} value={this.state.phone}/>
Der ordentlichste Ansatz
Hier ist ein Ansatz, den ich in meiner einfachen Anwendung verwendet habe. Dies ist der empfohlene Ansatz in React und es ist wirklich ordentlich und sauber. Es ist sehr nahe an der Antwort von ArneHugo und ich danke auch hm. Die Idee ist eine Mischung davon und reagiert auf Formulare. Wir können das name-Attribut jeder Formulareingabe verwenden, um den spezifischen propertyName abzurufen und den Status basierend darauf zu aktualisieren. Dies ist mein Code in ES6 für das obige Beispiel:
class ContactEdit extends React.Component {
handleChangeFor = (event) => {
const name = event.target.name;
const value = event.target.value;
const { contact } = this.state;
const newContact = {
...contact,
[name]: value
};
this.setState({ contact: newContact });
}
render() {
return (
<div>
<input type="text" name="firstName" onChange={this.handleChangeFor} />
<input type="text" name="lastName" onChange={this.handleChangeFor}/>
<input type="text" name="phone" onChange={this.handleChangeFor}/>
</div>
);
}
}
Die Unterschiede:
Wir haben hier weniger Code und es ist ein kluger Weg, jegliche Art von Eingaben aus dem Formular zu erhalten, da das Namensattribut für jede Eingabe einen eindeutigen Wert hat. Sehen Sie ein funktionierendes Beispiel Ich habe CodPen für meine experimentelle Bloganwendung in einem frühen Stadium.
<input>
-Elemente haben oft eine Eigenschaft namens name . Wir können auf diese name -Eigenschaft über das Ereignisobjekt zugreifen, das wir von einem Event-Handler erhalten:
Einen allgemeinen Änderungshandler schreiben
constructor () {
super();
this.state = {
name: '',
age: ''
};
this.handleChange = this.handleChange.bind(this);
}
handleChange (evt) {
this.setState({ [evt.target.name]: evt.target.value });
}
render () {
return (
<form>
<label>Name</label>
<input type="text" name="name" onChange={this.handleChange} />
<label>Age</label>
<input type="text" name="age" onChange={this.handleChange} />
</form>
);
}
handleChange(event){
this.setState({[event.target.name]:event.target.value});
this.setState({[event.target.name]:event.target.value});
}