How to handle multiple inputs in React 
Tags: react, webdev, codenewbie
Published: 2020-11-29 23:06:49

I recently had to refactor a React Form when working with multiple inputs and I thought I'd share how I did it. 

This is how my form looks like: 

![Screen Shot 2020-11-28 at 10.38.42 PM](https://dev-to-uploads.s3.amazonaws.com/i/agvyl252k24f8m71piek.png)

 
 
## The Problem 

* Look at the starter code below 
* This `Form` component has 5 input fields in total; 5 different states and 5 different `onChange` inline functions
* This is not exactly DRY code 🙀

```javascript 
import React, { useState } from "react";

export default function Form() {
  const [newCompany, setCompany] = useState("");
  const [newPosition, setPosition] = useState("");
  const [newLink, setNewLink] = useState("");
  const [newDate, setNewDate] = useState("");
  const [newNote, setNewNote] = useState("");

  return (
        <form>
          <input
            value={newCompany}
            onChange={(e) => setCompany(e.target.value)}
            label="Company"
          />
          <input
            value={newPosition}
            onChange={(e) => setPosition(e.target.value)}
            label="Job Title"
          />
          <input
            value={newLink}
            onChange={(e) => setNewLink(e.target.value)}
            label="Job Link"
          />
          <input
            type="date"
            value={newDate}
            onChange={(e) => setNewDate(e.target.value)}
          />
          <input
            value={newNote}
            onChange={(e) => setNewNote(e.target.value)}
            label="Note"
          />
          <button type="submit"> Submit </button>
        </form>
  );
}
```
* Also, if I want to add a `reset` function later, my code will look like this: 🙅🏽‍♀️  

```javascript
  const reset = () => {
    setCompany("");
    setPosition("");
    setNewLink("");
    setNewDate("");
    setNewNote("");
  };
```

## The Solution: Refactoring ✨

### Step 1: Add input default values and initialize state
* First, let's add default values to **ALL** input fields 
* How do we do that? We create an object literal with those values and set to empty string  
* Then, with the `useState()` React Hook we initialize our `values` state with the `initialValues` object
* **Important**: Remember to add the `value` attribute to every input field with its corresponding value (**e.g.** `values={values.company}`) 

```javascript 
const initialValues = {
  company: "",
  position: "",
  link: "",
  date: "",
  note: "",
};

export default function Form() {
  const [values, setValues] = useState(initialValues);
  
  return (
        <form>
          <input
            value={values.company}
            onChange={(e) => setCompany(e.target.value)}
            label="Company"
          />
 //...
```

### Step 2: Handle multiple input change 

* The goal here is to handle **ALL** inputs with a single `onChange` handler 
* In order to update and keep track of our input fields every time they change, we need to create a `handleInputChange` function (see below) 
* What's happening here? (quick recap)
 * First, we're using object destructuring to get or extract the `name` and the `value` attributes from our inputs (look at the the comments below - they're equivalent)
 * Then, we're updating our `values` state object with the *existing values* by using the `setValues()` function and the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) 
 * And finally, we're *updating* the `value` of the event that was triggered by that `onChange` with this ES6 syntax: `[name]: value`
 * This is a very **important** step! 
We need to add a `name` attribute to our inputs and `[name]: value` here means that we're setting a dynamic `name` property key (taken from our inputs - *e.g.* `company: e.target.value`) which will be equal to the `value` of our current input state.  

Reference: [React Docs](https://reactjs.org/docs/forms.html#handling-multiple-inputs) 

```javascript 
 //... 

  const handleInputChange = (e) => {
    //const name = e.target.name 
    //const value = e.target.value 
    const { name, value } = e.target;

    setValues({
      ...values,
      [name]: value,
    });
  };

  return (
        <form>
          <input
            value={values.company}
            onChange={handleInputChange}
            name="company" //IMPORTANT 
            label="Company"
          />
   // ... 
```

### Step 3: Add `handleInputChange` to input fields

* Add the `handleInputChange` function to the `onChange` prop of every input field 
* Look at the final code; this is a much cleaner and manageable form 👌🏽

```javascript 
import React, { useState } from "react";

const initialValues = {
  company: "",
  position: "",
  link: "",
  date: "",
  note: "",
};

export default function Form() {
  const [values, setValues] = useState(initialValues);
  
  const handleInputChange = (e) => {
    const { name, value } = e.target;
    setValues({
      ...values,
      [name]: value,
    });
  };

  return (
        <form>
          <input
            value={values.company}
            onChange={handleInputChange}
            name="company"
            label="Company"
          />
          <input
            value={values.position}
            onChange={handleInputChange}
            name="position"
            label="Job Title"
          />
           // ... Rest of the input fields
          <button type="submit"> Submit </button>
        </form>
  );
}
```

I hope it was useful. All comments and feedback are welcome! 🎊