In React.js, form handling is a crucial part of building interactive and dynamic web applications. When dealing with forms, there are two main approaches to managing the form data: Controlled Components and Uncontrolled Components. Understanding the differences between these two approaches is essential for managing state and achieving the desired user experience in your React applications.
Controlled components in React are those whose form data is controlled by React’s state. In other words, the value of the input elements (such as text inputs, checkboxes, etc.) is managed by the React component’s state. Any updates to the form input must go through the component’s state, and the React component has full control over the form elements.
setState
(or hooks like useState
).Let’s build a simple controlled component where a user types into an input field, and the text they type is stored and displayed in the component’s state.
import React, { useState } from 'react';
const ControlledComponent = () => {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
};
return (
The current input is: {value}
);
};
export default ControlledComponent;
useState
hook is used to define the value
state and the setValue
function that updates it.value
prop of the <input>
element is bound to the state (value
), meaning the input field always reflects the state’s value. When the user types something, the onChange
handler updates the state, and the input field rerenders with the updated state.When the user types in “Hello” into the input field, the displayed text below the input box updates in real-time to:
The current input is: Hello
Uncontrolled components in React manage their own state internally via the DOM, rather than using React’s state. With uncontrolled components, you don’t bind the form input’s value to the component state. Instead, you access the current value of the form input using refs when needed.
Now, let’s build an uncontrolled component where a user types into an input field, but the input value is retrieved using refs instead of managing it via state.
import React, { useRef } from 'react';
const UncontrolledComponent = () => {
const inputRef = useRef(null);
const handleSubmit = (event) => {
event.preventDefault();
alert(`Input value: ${inputRef.current.value}`);
};
return (
);
};
export default UncontrolledComponent;
useRef
hook to create a reference (inputRef
) to the input element. This reference allows us to access the input value without relying on React’s state.inputRef.current.value
.useState
to manage the input’s value. The input manages its value internally through the DOM.When the user submits the form, an alert will pop up showing the current input value (e.g., “Hello”).
Feature | Controlled Components | Uncontrolled Components |
---|---|---|
State Management | Managed by React's state (useState, setState) | Managed by the DOM itself using refs |
Form Input Control | Input value is controlled by the component’s state | Input value is controlled by the DOM |
Two-Way Data Binding | Yes (input value always reflects the state) | No (input value does not automatically sync with the state) |
When to Access Input Data | In real-time during input change | When necessary, e.g., on form submission |
Usage | Useful when you need real-time validation or control over form inputs | Useful when you don't need real-time control, and accessing data on demand is sufficient |
Controlled components give you more control over form input, making them perfect for form validation. Let’s see how we can use controlled components to perform basic validation on a form.
import React, { useState } from 'react';
const ControlledForm = () => {
const [email, setEmail] = useState('');
const [error, setError] = useState('');
const handleChange = (event) => {
setEmail(event.target.value);
// Simple email validation
if (!event.target.value.includes('@')) {
setError('Please enter a valid email.');
} else {
setError('');
}
};
const handleSubmit = (event) => {
event.preventDefault();
if (!error) {
alert(`Email submitted: ${email}`);
} else {
alert('Form contains errors.');
}
};
return (
);
};
export default ControlledForm;
handleChange
function checks if the input value contains an “@” symbol. If it doesn’t, it sets an error message in the state.When the user types an invalid email (e.g., “test”), the error message “Please enter a valid email.” appears, and the submit button is disabled.
Let’s see how we can handle form submissions using uncontrolled components, where the input values are retrieved only when needed.
import React, { useRef } from 'react';
const UncontrolledForm = () => {
const emailRef = useRef(null);
const passwordRef = useRef(null);
const handleSubmit = (event) => {
event.preventDefault();
const email = emailRef.current.value;
const password = passwordRef.current.value;
if (email && password) {
alert(`Email: ${email}, Password: ${password}`);
} else {
alert('Please fill out both fields.');
}
};
return (
);
};
export default UncontrolledForm;
useRef
to reference both the email and password fields.emailRef.current.value
and passwordRef.current.value
inside the handleSubmit
function.When the user submits the form, an alert box shows the entered email and password.
Controlled vs. Uncontrolled Components represent two different approaches to handling form data in React. Controlled components give you more control by keeping the form state within React, allowing for real-time updates and validations. Uncontrolled components are simpler and rely on the DOM for input management, which can be beneficial for simple forms or when performance is a concern. Happy Coding!❤️