I have a component that stores a contact object as state - {firstName: \"John\", lastName: \"Doe\", phone: \"1234567890} I want to create a form to edit this object but if I
The neatest approach
Here is an approach that I used in my simple application. This is the recommended approach in React and it is really neat and clean. It is very close to ArneHugo's answer and I thank hm too. The idea is a mix of that and react forms site. We can use name attribute of each form input to get the specific propertyName and update the state based on that. This is my code in ES6 for the above example:
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>
);
}
}
The differences:
We have less code here and vey smart way to get any kind input from the form because the name attribute will have a unique value for each input. See a working example I have in CodPen for my experimental blog application in its early stage.
ES6 one liner approach
<input type="text"
value={this.state.username}
onChange={(e) => this.setState({ username: e.target.value })}
id="username"/>
handleChange(event){
this.setState({[event.target.name]:event.target.value});
this.setState({[event.target.name]:event.target.value});
}
<input>
elements often have a property called name.
We can access this name property from the event object that we receive from an event handler:
Write a generalized change handler
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>
);
}
There are two ways to update the state of a nested object:
You can see how it works in this JS Fiddle. The code is also below:
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')
);
Here is generic one;
handleChange = (input) => (event) => {
this.setState({
...this.state,
[input]: event.target.value
});
}
And use like this;
<input handleChange ={this.handleChange("phone")} value={this.state.phone}/>