1

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?

3
  • 1
    You are setting state as copyState and also, why are you setting all fields to value? Commented Apr 14, 2018 at 13:55
  • As @Daniel Nilles said, you are overwhelming to change your state. State merges the changes if you do it correctly, you do not need copy the whole state every time. I suggest studying object spread syntax, it is very useful for most of state changes in React. I'm a learner too by the way. Commented Apr 14, 2018 at 14:05
  • What do you mean by "The input field in salary and headline is not accepting input from user"? Are you unable to type anything at all? Are you trying to type a $ or other monetary symbol? Did you try typing only numbers? Commented Apr 14, 2018 at 14:12

3 Answers 3

1

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 }})
}
Sign up to request clarification or add additional context in comments.

4 Comments

actually that would not work for account or topSkills
Oh yes, I missed the point for the nested keys and arrays. For dynamic changing we need to think an other approach. Thank you for pointing that out.
I would recommend sub components for those fields... but thats outside the op
@DanielNilles, for salary it should work but as said in the previous comments for other nested fields it does not work.
1

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: ''
    },
   ],
 }

3 Comments

I upvoted this answer since I could not find any better solution than creating separate functions to change the state as a noob :) I think there isn't an easy way to change the state like I did on plain fields right?
@Seth McClaine, salary is part of candidate variable, i have to pass through candidate before i reach salary. The function you suggested works when the state variable is not enclosed by object
@DanielNilles you're right, I've updated my response
0

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});
        };

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.