Daniel Nilles
Daniel Nilles

Reputation: 41

Reactjs setState issues from form inputs

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

Answers (3)

Daniel Nilles
Daniel Nilles

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

Seth McClaine
Seth McClaine

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

devserkan
devserkan

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

Related Questions