React FAQ: Top Questions
14. What are Controlled and Uncontrolled Components?
In React, forms and input elements (like <input>, <textarea>, <select>) can be managed in two primary ways: as **Controlled Components** or **Uncontrolled Components**. The choice depends on how you want to handle the input's state and data flow.
Controlled Components:
- Definition: A controlled component is an input form element whose value is controlled by React state. The state becomes the "single source of truth" for the input's value.
-
How it works:
- The input's
value(orcheckedfor checkboxes) is set by a state variable. - An
onChangeevent handler updates the state variable whenever the input value changes. - This creates a two-way data binding: the UI reflects the state, and user input updates the state.
- The input's
-
Pros:
- Easier to validate input.
- Easier to manipulate or transform input values (e.g., format text as the user types).
- Easier to manage form submission and reset.
- Predictable behavior and easier debugging.
-
Cons:
- Requires more boilerplate code (state, onChange handler for each input).
- Can lead to performance issues with very large forms if not optimized (though typically negligible).
Uncontrolled Components:
- Definition: An uncontrolled component is an input form element whose value is managed by the DOM itself, rather than by React state.
-
How it works:
- You typically use a
refto get direct access to the DOM element. - The input's value is retrieved directly from the DOM when needed (e.g., on form submission).
- It behaves more like traditional HTML forms.
- You typically use a
-
Pros:
- Less boilerplate code for simple inputs.
- Can be useful for integrating with non-React code or third-party DOM libraries.
-
Cons:
- Harder to validate input in real-time.
- Less control over the input's value.
- Harder to reset the form programmatically.
- Can be less "React-idiomatic."
In most modern React applications, **controlled components are preferred** because they provide more control and predictability over form data. Uncontrolled components are generally used for simpler cases or when direct DOM access is specifically required.
import React, { useState, useRef } from 'react';
import ReactDOM from 'react-dom/client';
// --- Controlled Component Example ---
function ControlledInput() {
const [inputValue, setInputValue] = useState('');
const handleChange = (event) => {
setInputValue(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault(); // Prevent default form submission behavior
alert(`Controlled Input Value: ${inputValue}`);
};
return (
<div className="swf-lsn-card p-4 mb-4">
<h3>Controlled Component</h3>
<form onSubmit={handleSubmit}>
<label className="block text-sm font-medium text-gray-700">
Name:
<input
type="text"
value={inputValue} {/* Value is controlled by state */}
onChange={handleChange} {/* State is updated on change */}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
/>
</label>
<button
type="submit"
className="px-4 py-2 mt-3 rounded-md bg-blue-600 text-white"
>
Submit Controlled
</button>
</form>
<p className="mt-2 text-sm text-gray-500">Live Value: {inputValue}</p>
</div>
);
}
// --- Uncontrolled Component Example ---
function UncontrolledInput() {
const inputRef = useRef(null); // Create a ref
const handleSubmit = (event) => {
event.preventDefault();
// Access value directly from the DOM using the ref
alert(`Uncontrolled Input Value: ${inputRef.current.value}`);
};
return (
<div className="swf-lsn-card p-4">
<h3>Uncontrolled Component</h3>
<form onSubmit={handleSubmit}>
<label className="block text-sm font-medium text-gray-700">
Email:
<input
type="email"
ref={inputRef} {/* Attach the ref to the input */}
defaultValue="test@example.com" {/* Initial value set here */}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-green-300 focus:ring focus:ring-green-200 focus:ring-opacity-50"
/>
</label>
<button
type="submit"
className="px-4 py-2 mt-3 rounded-md bg-green-600 text-white"
>
Submit Uncontrolled
</button>
</form>
<p className="mt-2 text-sm text-gray-500">
Value is read only on submit.
</p>
</div>>
);
}
// --- App Component ---
function App() {
return (
<div className="app-container swf-lsn-container">
<h1>Controlled vs. Uncontrolled Components</h1>
<ControlledInput />
<UncontrolledInput />
<div className="swf-lsn-list mt-8">
<p>
This example demonstrates the key differences between controlled and
uncontrolled components for form inputs.
</p>
</div>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Explanation of the Code:
-
ControlledInputComponent:-
Uses
useStateto manageinputValue. -
The
<input>element'svalueprop is bound toinputValue(value={inputValue}). -
The
onChangehandler (handleChange) updatesinputValuewith the current value from the input field. This ensures that React state is always the source of truth. - The "Live Value" paragraph updates immediately as you type, demonstrating real-time control.
-
Uses
-
UncontrolledInputComponent:-
Uses
useRefto create aref(inputRef). This ref is then attached to the<input>element (ref={inputRef}). -
defaultValue="test@example.com"sets the initial value, but after that, the DOM manages the input's value directly. -
On form submission (
handleSubmit), the input's value is accessed directly from the DOM viainputRef.current.value. React does not re-render the component as you type in this input.
-
Uses
- This example clearly illustrates the fundamental difference in how input values are managed and accessed in controlled versus uncontrolled components.
