0

I have a FORM which just needs to store the values in state on submit. I'm facing issue in doing so,

  1. I only get value of last input in my formcontrol i.e:

    formControls: qualification: "a"

  2. I get this error : Warning: A component is changing a controlled input of type text to be uncontrolled. Input elements should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

I understood the above issue so i declared my state inside constructor so my input element has the value even before onChange function is triggered. But this also doesn't seem to solve my issue.

Below is my code:

import React, { Component } from 'react';
import  './user.css';

class User extends Component {
    constructor(props){
        super(props);
            this.state = {
                formControls: {
                 name: "",
                 age: "",
                 occupation:"",
                 hometown: "",
                 qualification: ""
                } 
             }   
        }


    detailsHandler = (e) => {
       const name = e.target.name;
       const value = e.target.value;
       console.log(name, value)
       this.setState({
        formControls: {
          [name]: value
        }
    });
    }
    submitFormHandler    = (e) => {
        e.preventDefault();
        console.log(this.state)

    }
  render() {
    return (
      <div>
         <div className="main-container">
            <div className="form-header">
                <p className="">Fill details here</p>
            </div>
            <div className="form-container">
            <form onSubmit={this.submitFormHandler}>
            <div className="form-row">
                <div className="form-label"><label>Name: </label></div>
                <input type="text" placeholder="name" name="name" value={this.state.formControls.name} onChange={this.detailsHandler}/>
            </div>
            <div className="form-row">
            <div className="form-label"><label>Age: </label></div>

                <input type="text" placeholder="age"  name="age" value={this.state.formControls.age}  onChange={this.detailsHandler}/>
            </div>
            <div className="form-row">
            <div className="form-label"><label>Occupation: </label></div>

                <input type="text" placeholder="Occupation"  name="occupation" value={this.state.formControls.occupation}  onChange={this.detailsHandler}/>
            </div>
            <div className="form-row">
            <div className="form-label"><label>Hometown: </label></div>
                <input type="text" placeholder="Hometown"  name= "hometown" value={this.state.formControls.hometown}  onChange={this.detailsHandler}/>
            </div>
            <div className="form-row">
            <div className="form-label"><label>Qualification: </label></div>
                <input type="text" placeholder="Qualification" name="qualification" value={this.state.formControls.qualification}  onChange={this.detailsHandler}/>
            </div> 
            <div>

               <input type="submit" value="SUBMIT" />
            </div>
            </form>
            </div>
        </div>
      </div>
    );
  }
}

export default User;

Can someone help me to figure what I'm doing wrong?

AConsumer
  • 2,461
  • 2
  • 25
  • 33
Adarsh
  • 46
  • 1
  • 8

1 Answers1

0

I think the issue comes from how you are setting state. As far as I know state updates are merges shallowly (https://reactjs.org/docs/state-and-lifecycle.html#state-updates-are-merged) which means that when you update the state you are erasing the values for the other form controls.

this.setState({
    formControls: {
      [name]: value  // the other values will be lost except for [name]
    }
});

You'll want to merge the form control values from the current state or include all of the values manually in the state update call.

const oldFormControls = this.state.formControls;
const newFormControls = Object.assign(oldFormControls,  {
    [name]: value
});

this.setState({
   formControls: newFormControls
});

Something like that.

Edit: When the form values are lost (null) then React puts the input in uncontrolled mode.

lemieuxster
  • 1,081
  • 7
  • 14
  • This is not true. `setState` only overrides the values you specify, leaving the others intact. – Dor Shinar Feb 16 '19 at 07:31
  • Unless a newer version of React has addressed this then it doesn't do recursive merging https://stackoverflow.com/questions/18933985/this-setstate-isnt-merging-states-as-i-would-expect – lemieuxster Feb 16 '19 at 07:34
  • Oh sorry I see, I missed the fact he is overriding formControls inside the state. In this case you are correct. – Dor Shinar Feb 16 '19 at 07:36
  • Okay understood the issue.. this works fine . Thanks a lot for your help. – Adarsh Feb 16 '19 at 07:49