Reputation: 956
How do I write a single setState method to update the value for multiple input elements when the state object is nested as shown below?
Note: State shouldn't be mutated
When the state is not nested, we could do it like:
this.setState({ [event.target.name]: event.target.value });
But how do we do it when the state object is nested?
class FormContainer extends Component {
constructor () {
this.state = {
formControls: {
email: {
value: ''
},
user: {
value: ''
},
password: {
value: ''
}
}
}
}
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
this.setState({
//code here
});
}
render() {
return (
<form>
<input type="email"
name="email"
value={this.state.formControls.email.value}
onChange={this.changeHandler}
/>
<input type="text"
name="user"
value={this.state.formControls.name.value}
onChange={this.changeHandler}
/>
<input type="password"
name="password"
value={this.state.formControls.password.value}
onChange={this.changeHandler}
/>
</form>
);
}
}
Upvotes: 2
Views: 73
Reputation: 39270
You mixed up email and name, here is a working example:
class Component extends React.Component {
state = {
formControls: {
email: {
value: '',
},
name: {
value: '',
},
password: {
value: '',
},
},
};
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
this.setState({
...this.state,//copy state
formControls: {//set state.formControls
...this.state.formControls,//copy sate.formControls
[name]: {//set state.formControls[name]
...this.state.formControls[name],//copy state.formControls[name]
value,//set state.formControls[name].value
},
},
});
};
render() {
return (
<form>
<input
type="email"
name="email"
value={this.state.formControls.email.value}
onChange={this.changeHandler}
/>
<input
type="text"
name="name"
value={this.state.formControls.name.value}
onChange={this.changeHandler}
/>
<input
type="password"
name="password"
value={this.state.formControls.password.value}
onChange={this.changeHandler}
/>
</form>
);
}
}
//render app
ReactDOM.render(
<Component />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Setting nested values with spread will get messy very quickly, let's say I want to change month of data.person.dateOfBirth:
const data = {
person: {
dateOfBirth: {
month: 12,
year: 1999,
day: 31,
},
},
};
I have to copy every nest level when using spread:
const newDataWithDifferentMonth = {
...data, //copy data
person: {
...data.person, //copy data.person
dateOfBirth: {
...data.person.dateOfBirth, //copy data.person.dateOfBirth
month: 11,
},
},
};
To help with that you can write a helper that will clean up the code:
const newDataWithDifferentMonth = set(
data,
['person', 'dateOfBirth', 'month'],
() => 11
);
Upvotes: 2
Reputation: 2087
There are multiple ways to change the nested state object.
deepClone
.code:
changeHandler = event => {
const inputName = event.target.name;
const inputValue = event.target.value;
let updatedFormState = Object.assign({}, this.state);
updatedFormState.form[inputName].value = inputValue;
this.setState(updatedFormState);
}
Upvotes: 0
Reputation: 22363
this.setState((prevState) => ({
...prevState,
[name]: value,
}));
Upvotes: 0