DEV Community

loading...

How to handle multiple inputs in React

deboragaleano profile image Debora Galeano ・3 min read

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

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 πŸ™€
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>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • Also, if I want to add a reset function later, my code will look like this: πŸ™…πŸ½β€β™€οΈ
  const reset = () => {
    setCompany("");
    setPosition("");
    setNewLink("");
    setNewDate("");
    setNewNote("");
  };
Enter fullscreen mode Exit fullscreen mode

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})
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"
          />
 //...
Enter fullscreen mode Exit fullscreen mode

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
    • 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

 //... 

  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"
          />
   // ... 
Enter fullscreen mode Exit fullscreen mode

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 πŸ‘ŒπŸ½
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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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

Discussion (6)

pic
Editor guide
Collapse
donchocska profile image
donchocska

Amazing perofrmance. Very thanks!

Collapse
jokanic profile image
Jokanic

Really clean.

Collapse
yahaya_hk profile image
Yahaya Kehinde

Amazing Deborah ! ☺️☺️

Collapse
juliojeanfils1 profile image
Julio Jean Fils

Thank you

Collapse
omokay profile image
Omoke Chuku

This is beautiful!

Collapse
majidmo49787329 profile image
Majid Mohamed

Amazing perofrmance. Very thanks!