Reputation: 41
I am new to react world, I can't manage to change the state properly from form input field. I am building an employee profile that is going to be saved in a database. I created a profile in component state and get user data from the input field. But however, salary and headline fields are not changing while OnChange event handling function. Candidate is an object representation of employee
this.state = {
candidate: {
account: {
firstName: '',
lastName: '',
email: '',
phone: '',
},
salary: '',
headline: '',
topSkills: [{
experience1: '',
title1: ''
}, {
experience2: '',
title2: ''
}, {
experience3: '',
title3: ''
},
],
}
}
onChangefunction
handleChange(e) {
const name = e.target.name;
const value = e.target.value;
let copyState = Object.assign({},
this.state.candidate);
copyState.account[name] = value;
copyState.topSkills[name] = value;
copyState.salary = value;
copyState.headline = value;
this.setState(copyState);
}
The input field in salary and headline is not accepting input from user
<input
name="salary"
type="number"
value={this.state.candidate.salary|| ''}
onChange={this.handleChange}
/>
Can anyone provide me with help and suggest how to structure setState on onChange function?
Upvotes: 1
Views: 1716
Reputation: 41
Credit to udemy academy MLR — Teaching Assistant. He solved this way,the answer solve the problem.
handleChange = e => {
const candidateClone = Object.assign({}, this.state.candidate);// Shallow clone.
const accountClone = Object.assign({}, this.state.candidate.account);// Deep clone.
const topSkillsClone = Object.assign({}, this.state.candidate.topSkills);// Deep clone.
// below (let): Persists the last entered value (required).
let myHeadline = candidateClone.headline;
let myFirstName = candidateClone.account.firstName;
let mySalary = candidateClone.salary;
let myTopSkillsTitle = candidateClone.topSkills[0].title;
switch (e.target.name) {
case "headlineInput": // name in input field
myHeadline = e.target.value;
break;
case "firstNameInput": // name in input field
myFirstName = e.target.value;
break;
case "salaryInput":
mySalary = e.target.value;
break;
case "topSkillsTitleInput": // name in input field
myTopSkillsTitle = e.target.value;
break;
default:
console.log("Switch statement error");
}
accountClone.firstName = myFirstName;// Place the property value inside the deep cloned embedded object.
topSkillsClone[0].title = myTopSkillsTitle;// Place the property value inside the deep cloned embedded array.
candidateClone["account"] = accountClone;// Place the deep cloned embedded object inside the shallow cloned main object.
candidateClone["salary"] = mySalary;// Place the property inside the shallow cloned main object.
candidateClone["headline"] = myHeadline;// Place the property inside the shallow cloned main object.
candidateClone["topSkills"] = topSkillsClone;// Place the deep cloned embedded array inside the shallow cloned main object.
this.setState({candidate:candidateClone});
};
Upvotes: 0
Reputation: 10030
SetState does not required the entire object just what you are updating in the state.
Based on what you already have you could just do this
handleChange(e) {
const name = e.target.name;
const value = e.target.value;
this.setState({
account[name]: value,
topSkills[name]: value,
salary: value,
headline: value,
});
}
Though looking at your implementation, I'm not sure you will achieve what you want here... It looks like if you updated Salary, you account[name]
, topSkills[name]
, and 'headline` would be updated to the value you entered for salary.
As devserkan mentioned you can update one field at a time with setState
so what you could do is...
<input
name="salary"
type="number"
value={this.state.candidate.salary|| ''}
onChange={(e)=>this.setState({ salary: e.currentTarget.value })}/>
This is slightly inefficient because it would recreate the onChange function on every render. Your approach of creating a function outside the render in this case better...
handleSalaryChange { (e)=>this.setState({ salaray: e.currentTarget.value }); }
handleHeadlineChange { (e)=>this.setState({ headline: e.currentTarget.value }); }
render{ return (
<div>
<input
name="salary"
type="number"
value={this.state.candidate.salary|| ''}
onChange={this.handleSalaryChange)}/>
<input
name="headline"
value={this.state.candidate.headline|| ''}
onChange={this.handleHeadlineChange)}/>
...
</div>
)}
UPDATE For the handle*Change
functions to work as they are currently, state
would need to be updated to remove the candidate
wrapper....
state = {
account: {
firstName: '',
lastName: '',
email: '',
phone: '',
},
salary: '',
headline: '',
topSkills: [
{
experience1: '',
title1: ''
},
{
experience2: '',
title2: ''
},
{
experience3: '',
title3: ''
},
],
}
Upvotes: 1
Reputation: 17598
You can simply handle changes like that for inputs:
state = {
candidate: {
account: {
firstName: '',
lastName: '',
email: '',
phone: '',
},
salary: '',
headline: '',
topSkills: [
{
experience1: '',
title1: ''
},
{
experience2: '',
title2: ''
},
{
experience3: '',
title3: ''
},
],
}
}
handleChange = (e) => {
this.setState( { candidate: { [e.target.name]: e.target.value }})
}
Upvotes: 1