J'ai un composant qui stocke un objet de contact comme état - {prénom: "John", nom: "biche", téléphone: "1234567890} je veux créer un formulaire pour éditer cet objet mais si je veux que les entrées contiennent la valeur Pour le paramètre contact d'origine, il faut que chaque entrée soit contrôlée, mais je ne sais pas comment créer une fonction handleChange qui sera ajustée à chaque paramètre car mon état ne contient que {contact: {...}}. Voici ce que j'ai actuellement -
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>
);
}
Je souhaite dans ma poignéeChange je peux faire quelque chose comme
handleChange: function (event) {
this.setState({contact.firstName: event.target.value });
}
Il existe un moyen "simple" de le faire et un moyen "intelligent". Si vous me le demandez, faire les choses intelligemment n’est pas toujours le meilleur choix, car je pourrais avoir plus de difficulté à travailler plus tard. Dans ce cas, les deux sont très compréhensibles.
Note latérale: Je voudrais vous demander une chose à savoir: devez-vous mettre à jour l'objet contact
ou pouvez-vous simplement garder firstName
etc. directement sur l'état? Peut-être que vous avez beaucoup de données dans l'état du composant? Si tel est le cas, c'est probablement une bonne idée de le séparer en composants plus petits avec des responsabilités plus étroites.
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>
);
}
Cette section contient les mêmes exemples que ceux illustrés ci-dessus, mais en utilisant les fonctionnalités de ES2015 +.
Pour prendre en charge les fonctionnalités suivantes sur tous les navigateurs, vous devez transpiler votre code avec Babel en utilisant par exemple Les préréglages es2015 et réactifs , .__ et le plugin. stage-0 .
Vous trouverez ci-dessous des exemples mis à jour, en utilisant destructuring d'objet pour obtenir le contact de l'état, opérateur de propagation en Créer un objet contact mis à jour au lieu de le transformer , créer des composants comme Classes par étendre React.Component , et utiliser fonctions de flèche pour créer des rappels afin que nous ne puissions pas Je n'ai pas à 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>
);
}
}
Notez que handleChangeFor
est une fonction curry _: L'appeler avec une propertyName
crée une fonction de rappel qui, lorsqu'elle est appelée, met à jour [propertyName]
de l'objet contact (Nouveau) dans l'état.
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 approche one liner
<input type="text"
value={this.state.username}
onChange={(e) => this.setState({ username: e.target.value })}
id="username"/>
Il existe deux manières de mettre à jour l'état d'un objet imbriqué:
Vous pouvez voir comment cela fonctionne dans ce JS Fiddle . Le code est également ci-dessous:
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')
);
Voici un générique;
handleChange = (input) => (event) => {
this.setState({
...this.state,
[input]: event.target.value
});
}
Et utiliser comme ça;
<input handleChange ={this.handleChange("phone")} value={this.state.phone}/>
L'approche la plus soignée
Voici une approche que j'ai utilisée dans mon application simple. C'est l'approche recommandée dans React et c'est vraiment net et net. C'est très proche de la réponse d'ArneHugo et je le remercie aussi. L'idée est un mélange de cela et de site de formes de réaction. Nous pouvons utiliser l'attribut name de chaque entrée de formulaire pour obtenir le propertyName spécifique et mettre à jour l'état en fonction de cela. Voici mon code dans ES6 pour l'exemple ci-dessus:
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>
);
}
}
Les différences:
Nous avons moins de code ici et un moyen très intelligent d’obtenir une entrée quelconque dans le formulaire car l’attribut name aura une valeur unique pour chaque entrée. Voir un exemple de travail exemple dans CodPen pour mon application de blog expérimental à ses débuts.
Les éléments <input>
ont souvent une propriété appelée nom . Nous pouvons accéder à cette propriété name à partir de l'objet événement que nous recevons d'un gestionnaire d'événements:
Ecrire un gestionnaire de changement généralisé
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});
}