user
user

Reputation: 759

ReactJS: Single onChange handler for multiple form inputs

I have a form with text and number input types. In my react app, I maintain a nested object formInput in the component state with all the form field values:

this.state = {
// Other state variables
    formInput: {
    name1:'',
    name2:'',
    numberInput1:0,
    numberInput2:0
  }
}

I am very new to React and in my app, I currently have a handleOnChange() method for each input which is a really crude way of doing it. Is there a way to write a single handleOnChange() function that will update my components state when an input is changed?

I tried this:

handleOnChange(evt) {
    this.setState({[evt.target.name]: evt.target.value});
}

But this method works if the form input fields aren't nested inside the formInput object of my components state. Is there a different way to have a single onChange handler for fields within an object?

Upvotes: 1

Views: 396

Answers (2)

Dacre Denny
Dacre Denny

Reputation: 30360

You could adapt your handleOnChange() method to work with nested formInput by doing something like this:

handleOnChange(evt) {

    /* Pass callback to setState instead (optional) */
    this.setState(({ formInput }) => {

      /* Compose next state object, with nested formInput
      describing the updated value state of the form */
      const nextState = { 
        formInput : { 
            ...formInput, 
            [evt.target.name]: evt.target.value
          } 
      }

      return nextState;
    });
}

Update

If spread syntax is not available due to your build configuration or target browser, a "non-spread" equivalent can be implemented with Object.assing() like this:

handleOnChange(evt) {

    /* Extract name and value from event target */
    const { name, value } = evt.target;

    this.setState(({ formInput }) => {

      const nextState = { 

        /* Use Object.assign() as alternate to ... syntax */
        formInput : Object.assign({}, formInput, { [name]: value })
      }

      return nextState;
    });
}

Upvotes: 1

Titus
Titus

Reputation: 22474

Yes you can do that, you can use something like:

handleOnChange(evt) {
  this.setState(prevState => ({
    formInput: {
        ...prevState.formInput,
        [evt.target.name]: evt.target.value
       }
    }));
}

Upvotes: 1

Related Questions