Forms are a crucial part of web applications, enabling user interaction through data input. In React, handling forms efficiently involves using controlled components. Controlled components are React components that manage their own state through React state, ensuring that the form data is controlled by the React component rather than the DOM.
Controlled components offer a robust way to handle form data, allowing for easy validation, conditional rendering, and state management. By understanding and utilizing controlled components, developers can create dynamic and interactive forms that respond to user input seamlessly.
What are Controlled Components?
Controlled components in React are input elements whose values are controlled by the React component’s state. This approach allows React to have full control over the form data, making it easier to manage and manipulate.
In a controlled component, the form data is handled by the component state, and any changes to the input values trigger state updates. This ensures that the component’s state is always in sync with the input elements, providing a single source of truth for the form data.
Setting Up a Basic Controlled Component
To create a controlled component, you need to set up an input element that is controlled by the React component’s state. Here is an example of a simple controlled input component:
import React, { useState } from 'react';
function ControlledInput() {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
};
return (
<div>
<label>
Enter text:
<input type="text" value={value} onChange={handleChange} />
</label>
<p>You entered: {value}</p>
</div>
);
}
export default ControlledInput;
In this example, the ControlledInput
component uses the useState
hook to manage the value of the input element. The handleChange
function updates the state whenever the input value changes, ensuring that the component state and input value are always in sync.
Handling Multiple Inputs
When dealing with forms that have multiple input elements, you can extend the controlled component pattern to manage multiple state values. Here is an example of a controlled form with multiple inputs:
import React, { useState } from 'react';
function ControlledForm() {
const [formData, setFormData] = useState({ name: '', email: '' });
const handleChange = (event) => {
const { name, value } = event.target;
setFormData((prevData) => ({ ...prevData, [name]: value }));
};
return (
<form>
<div>
<label>
Name:
<input type="text" name="name" value={formData.name} onChange={handleChange} />
</label>
</div>
<div>
<label>
Email:
<input type="email" name="email" value={formData.email} onChange={handleChange} />
</label>
</div>
<p>Name: {formData.name}</p>
<p>Email: {formData.email}</p>
</form>
);
}
export default ControlledForm;
In this example, the ControlledForm
component uses a single state object to manage multiple input values. The handleChange
function updates the state dynamically based on the name
attribute of the input elements, allowing for efficient management of multiple inputs.
Controlled Components for Select, Checkbox, and Radio
Example of Controlled Select
Controlled components can also be used with select
elements. Here is an example of a controlled select
component:
import React, { useState } from 'react';
function ControlledSelect() {
const [selectedOption, setSelectedOption] = useState('option1');
const handleChange = (event) => {
setSelectedOption(event.target.value);
};
return (
<div>
<label>
Choose an option:
<select value={selectedOption} onChange={handleChange}>
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
<option value="option3">Option 3</option>
</select>
</label>
<p>Selected option: {selectedOption}</p>
</div>
);
}
export default ControlledSelect;
In this example, the ControlledSelect
component manages the selected value of the select
element using the useState
hook. The handleChange
function updates the state whenever a different option is selected.
Example of Controlled Checkbox
Here is an example of a controlled checkbox component:
import React, { useState } from 'react';
function ControlledCheckbox() {
const [isChecked, setIsChecked] = useState(false);
const handleChange = (event) => {
setIsChecked(event.target.checked);
};
return (
<div>
<label>
<input type="checkbox" checked={isChecked} onChange={handleChange} />
Accept terms and conditions
</label>
<p>Checkbox is {isChecked ? 'checked' : 'unchecked'}</p>
</div>
);
}
export default ControlledCheckbox;
In this example, the ControlledCheckbox
component uses the useState
hook to manage the checked state of the checkbox. The handleChange
function updates the state based on the checked
property of the input element.
Example of Controlled Radio Buttons
Here is an example of a controlled radio button component:
import React, { useState } from 'react';
function ControlledRadioButtons() {
const [selectedOption, setSelectedOption] = useState('option1');
const handleChange = (event) => {
setSelectedOption(event.target.value);
};
return (
<div>
<label>
<input
type="radio"
value="option1"
checked={selectedOption === 'option1'}
onChange={handleChange}
/>
Option 1
</label>
<label>
<input
type="radio"
value="option2"
checked={selectedOption === 'option2'}
onChange={handleChange}
/>
Option 2
</label>
<p>Selected option: {selectedOption}</p>
</div>
);
}
export default ControlledRadioButtons;
In this example, the ControlledRadioButtons
component manages the selected value of the radio buttons using the useState
hook. The handleChange
function updates the state whenever a different radio button is selected.
Validating Form Inputs
Form validation is essential for ensuring that user input meets specific criteria before submission. Controlled components make it easy to implement validation logic within your React components.
Here is an example of a form with validation:
import React, { useState } from 'react';
function ValidatedForm() {
const [formData, setFormData] = useState({ name: '', email: '' });
const [errors, setErrors] = useState({});
const handleChange = (event) => {
const { name, value } = event.target;
setFormData((prevData) => ({ ...prevData, [name]: value }));
};
const handleSubmit = (event) => {
event.preventDefault();
const newErrors = {};
if (!formData.name) newErrors.name = 'Name is required';
if (!formData.email) {
newErrors.email = 'Email is required';
} else if (!/\S+@\S+\.\S+/.test(formData.email)) {
newErrors.email = 'Email is invalid';
}
setErrors(newErrors);
if (Object.keys(newErrors).length === 0) {
alert('Form submitted successfully');
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>
Name:
<input type="text" name="name" value={formData.name} onChange={handleChange} />
</label>
{errors.name && <p style={{ color: 'red' }}>{errors.name}</p>}
</div>
<div>
<label>
Email:
<input type="email" name="email" value={formData.email} onChange={handleChange} />
</label>
{errors.email && <p style={{ color: 'red' }}>{errors.email}</p>}
</div>
<button type="submit">Submit</button>
</form>
);
}
export default ValidatedForm;
In this example, the ValidatedForm
component includes basic validation logic for the name
and email
fields. The handleSubmit
function checks for validation errors and updates the errors
state accordingly. If there are no validation errors, the form is submitted successfully.
Conclusion
Controlled components are a fundamental concept in React that allow developers to manage form data efficiently. By controlling the input values through the component state, React ensures that the form data is always in sync with the component state, providing a single source of truth.
In this article, we explored how to set up basic controlled components, handle multiple inputs, and manage various input types such as select
, checkbox
, and radio
buttons. We also discussed form validation and best practices for using controlled components in React. By applying these techniques, you can create dynamic and interactive forms that respond seamlessly to user input.