Handling Multiple Inputs in ReactJS: Best Practices for React JS Input Forms

Learn How to Get Input Values in ReactJS and Effectively Manage Multiple Input Forms for Seamless User Experience

Amit Sharma
4 min readApr 23, 2023

This blog is a continuation of my previous blog, where I have created custom inputs and button components.

Handling many inputs can be difficult when developing complicated user interfaces using ReactJS. One popular method is to use the useState hook to handle the state of each input field independently and update it as the value changes. However, as the number of inputs increases, this strategy can soon become inefficient and difficult to maintain.

Consider the following simple example of a form component with many input fields for gathering user information: name, business name, email, and password. If we use the useState hook to control the state of each input field individually, the code could look like this:

import './App.css'
import CustomInput from './components/CustomInput'
import { AiOutlineMail, AiFillLock, AiOutlineUser } from 'react-icons/ai'
import FormButton from './components/FormButton'
import { useState } from 'react';

function App() {

const [name, setName] = useState("");
const [businessName, setBusinessName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");


const handleSubmit = (e) => {
e.preventDefault();
console.log(name,businessName,email,password);
};


return (
<>
<main>
<form onSubmit={handleSubmit}>
<CustomInput icon={<AiOutlineUser />} onChange={(e) => setName(e.target.value)} type={'text'} placeholder={'Enter User Name'} />
<CustomInput icon={<AiOutlineUser />} onChange={(e) => setBusinessName(e.target.value)} type={'text'} placeholder={'Enter Business Name'} />
<CustomInput icon={<AiOutlineMail />} onChange={(e) => setEmail(e.target.value)} type={'text'} placeholder={'Enter your Email'} />
<CustomInput icon={<AiFillLock />} onChange={(e) => setPassword(e.target.value)} type={'password'} placeholder={'Enter your Password'} />
<FormButton btnText={'Click to Proceed'} />
</form>

</main>
</>
)
}
export default App

In the above code I am using React functional component that renders a form with several custom input fields and a submit button. The component uses the useState hook to manage the state of the form inputs, including the user’s name, business name, email, and password individually.

While this method works well for a limited number of inputs, it quickly becomes difficult and wasteful as the number of inputs increases.

For example, if a form had 10 input fields, ten separate useState hooks, each with its own setter method, would be required. This method can soon become complex , particularly if the form requirements change regularly.

Because using setState for every input value change can lead to unnecessary re-renders and poor performance, which can negatively impact the user experience. Additionally, managing each input separately can make the codebase harder to read and modify, leading to potential bugs and errors.

The better approach:

One alternative approach is to use a single useState hook to manage the state of the entire form as an object, like this:

import './App.css'
import CustomInput from './components/CustomInput'
import { AiOutlineMail, AiFillLock, AiOutlineUser } from 'react-icons/ai'
import FormButton from './components/FormButton'
import { useState } from 'react';

function App() {

const [formData, setFormData] = useState({
name: "",
email: "",
businessName: "",
password: "",
});

const handleInputChange = (e) => {
const { name, value } = e.target;
setFormData((prevFormData) => ({
...prevFormData,
[name]: value,
}));
};

const handleSubmit = (e) => {
e.preventDefault();
console.log(formData);
};

return (
<>
<main>
<form onSubmit={handleSubmit}>
<CustomInput
icon={<AiOutlineUser />}
onChange={handleInputChange}
value={formData.name}
name="name"
type={'text'}
placeholder={'Enter User Name'}
/>

<CustomInput
icon={<AiOutlineUser />}
onChange={handleInputChange}
value={formData.businessName}
name="businessName"
type={'text'}
placeholder={'Enter Business Name'}
/>

<CustomInput
icon={<AiOutlineMail />}
onChange={handleInputChange}
value={formData.email}
name="email"
type={'text'}
placeholder={'Enter your Email'}
/>

<CustomInput
icon={<AiFillLock />}
onChange={handleInputChange}
value={formData.password}
name="password"
type={'password'}
placeholder={'Enter your Password'}
/>

<FormButton btnText={'Click to Proceed'} />
</form>

</main>
</>
)
}
export default App

In this approach, we’re using a single useState hook to manage the state of the entire form as an object. We’re also using a single event handler function to handle input changes , creating an object with key-value pairs for each input field and using the spread operator to update the state object. This approach is more efficient, easier to maintain, and can be easily extended to handle more complex forms with multiple input fields.

To summarise, while it is technically possible to use the useState for every input in a React component, it is not generally advised because of to code duplication and performance issues. Instead, use a single useState hook to manage the entire form’s state, or use a form management library like Formik or React Hook Form.

We can produce simpler and more efficient code that is easier to maintain and scale over time by following best practises for managing form input state in React. Furthermore, by weighing the trade-offs between alternative approaches, we may make intelligent decisions about which solution is appropriate for our specific use case.

If you find it useful, consider buying me a coffee! ☕️

If you are a front-end developer you definitely want to check out some of javascript’s advanced concepts -

React form design

Explicit binding

Memoization in javascript

--

--

Amit Sharma

Front-end developer sharing coding tips and life lessons. Join me for tech insights and personal growth advice to enhance your career and life.