What is an Un-Controlled Component in React?
In React, uncontrolled components refer to components where form data is handled by the DOM itself, rather than React state. The form fields (like <input>
, <textarea>
, <select>
, etc.) rely on the browser to manage their state. React simply references these DOM elements when needed.
How Uncontrolled Components Work in Your Example
Key Points in the Example:
-
No
state
Management in React:- The form fields (
<input>
,<checkbox>
, etc.) do not useuseState
orsetState
to track their values. - Instead, the browser manages their state natively, and React interacts with them when necessary.
- The form fields (
-
Default Values:
- You use attributes like
defaultValue
anddefaultChecked
to set the initial values for the form fields:defaultValue="Some initial value"
for the text input.defaultChecked={true}
for the checkbox and radio buttons.
- These attributes provide the initial value without locking the input to React state.
- You use attributes like
-
Reading Values on Submission:
- Instead of tracking values using React’s state (controlled components), the values are read directly from the DOM when the form is submitted.
-
The
handleSubmit
function reads the data using theFormData
API:const form = e.target; const formData = new FormData(form);
This allows you to collect all form field values as key-value pairs at the time of submission.
-
Interoperability with Fetch and JSON:
-
The
FormData
object can be directly passed as the body of afetch
request, or it can be converted to a plain object with:const formJson = Object.fromEntries(formData.entries());
-
This ensures that the form data is processed dynamically at submission, rather than being managed in React.
-
Advantages of Uncontrolled Components
-
Minimal React State Management:
- Since the browser handles form states, you don’t need to set up
useState
for every input. - Great for simple forms or legacy codebases transitioning to React.
- Since the browser handles form states, you don’t need to set up
-
Native Form Handling:
- Leveraging the native
FormData
API makes it easy to handle form submissions, especially when sending data to an API or backend.
- Leveraging the native
-
Less Boilerplate Code:
- No need to write
onChange
handlers for every field or update React state on every user interaction.
- No need to write
Default vs. Controlled Fields
Attribute | Uncontrolled Component | Controlled Component |
---|---|---|
Initial Value | defaultValue / defaultChecked | value / checked |
Value Management | Managed by the DOM | Managed via React useState or props |
Use Case | Simple forms, less frequent updates | Complex forms, real-time validation or updates |
What Happens in the Example?
Text Input:
<input name="myInput" defaultValue="Some initial value" />
defaultValue
sets the initial value to"Some initial value"
.- The user can freely update the input, but React does not track its state.
- At form submission, the value is retrieved via the
FormData
API.
Checkbox:
<input type="checkbox" name="myCheckbox" defaultChecked={true} />
defaultChecked
initializes the checkbox as checked.- The checkbox’s state is independent of React and is updated directly by the user.
Radio Buttons:
<input type="radio" name="myRadio" value="option2" defaultChecked={true} />
- The
defaultChecked
attribute pre-selects “Option 2”. - Only one radio button is selected at a time based on the group (
name="myRadio"
).
- The
Form Submission:
- When the form is submitted, the
handleSubmit
function:- Prevents the default browser behavior (
e.preventDefault()
). - Reads the values of all form fields using the
FormData
API. - Logs the form data or sends it via
fetch
.
- Prevents the default browser behavior (
Why Use Uncontrolled Components?
- Simple Forms: Great for basic forms where you don’t need to monitor or manipulate field values in real-time.
- Native Browser Features: Allows you to use browser form features like
autofill
,validation
, and resetting with minimal React involvement. - Performance: No React state updates on every keystroke; the browser handles the state efficiently.
When to Use Controlled Components Instead?
- Real-Time Validation: If you need to validate inputs as the user types.
- Dynamic Form Behavior: If the UI reacts to form field changes (e.g., enabling/disabling a button based on input).
- Pre-Filled Inputs with Updates: If initial values are fetched from a server and can change dynamically.
In summary, uncontrolled components like in your example work by delegating state management to the DOM, with React handling events and submission. This approach is simple and effective for basic forms.
Example from React.dev
export default function MyForm() {
function handleSubmit(e) {
// Prevent the browser from reloading the page
e.preventDefault();
// Read the form data
const form = e.target;
const formData = new FormData(form);
// You can pass formData as a fetch body directly:
fetch('/some-api', { method: form.method, body: formData });
// Or you can work with it as a plain object:
const formJson = Object.fromEntries(formData.entries());
console.log(formJson);
}
return (
<form method="post" onSubmit={handleSubmit}>
<label>
Text input: <input name="myInput" defaultValue="Some initial value" />
</label>
<hr />
<label>
Checkbox: <input type="checkbox" name="myCheckbox" defaultChecked={true} />
</label>
<hr />
<p>
Radio buttons:
<label><input type="radio" name="myRadio" value="option1" /> Option 1</label>
<label><input type="radio" name="myRadio" value="option2" defaultChecked={true} /> Option 2</label>
<label><input type="radio" name="myRadio" value="option3" /> Option 3</label>
</p>
<hr />
<button type="reset">Reset form</button>
<button type="submit">Submit form</button>
</form>
);
}