Uncontrolled Components and `useRef`: When and Why to Use Them #75
📖 Introduction
Following our deep dive into Controlled Components for Forms (Part 2), this article explores an alternative approach: Uncontrolled Components. We will learn how to use the useRef
hook to manage form inputs and understand the scenarios where this pattern is a better choice than controlled components.
📚 Prerequisites
Before we begin, please ensure you have a solid grasp of the following concepts:
- Controlled Components
- The
useRef
hook - Basic understanding of the DOM and how it differs from the Virtual DOM
🎯 Article Outline: What You'll Master
In this article, you will learn:
- ✅ Foundational Theory: The core principles and mental models behind Uncontrolled Components.
- ✅ Core Implementation: How to use the
useRef
hook to access form input values directly from the DOM. - ✅ Practical Application: Building a simple form using uncontrolled components.
- ✅ Key Differences: A clear comparison between controlled and uncontrolled components.
- ✅ Best Practices & Anti-Patterns: When to use uncontrolled components and when to avoid them.
🧠 Section 1: The Core Concepts of Uncontrolled Components
In an uncontrolled component, the form data is handled by the DOM itself, not by the React component's state. This means that the DOM is the "single source of truth" for the input's value. To get the value from an uncontrolled component, you need to "pull" it from the DOM when you need it, typically using a ref.
Key Principles:
- DOM as the Source of Truth: The DOM manages the state of the form element.
- Refs for Access: We use the
useRef
hook to create a reference to the DOM element and access its value. - Less Re-renders: Because we are not updating state on every keystroke, uncontrolled components do not cause the component to re-render every time the input value changes.
💻 Section 2: Deep Dive - Implementation and Walkthrough
Let's see how to implement an uncontrolled component using the useRef
hook.
2.1 - Your First Example: A Simple Uncontrolled Input
Here is a foundational example demonstrating a single uncontrolled input:
// code-block-1.jsx
import React, { useRef } from 'react';
function SimpleUncontrolledForm() {
const inputRef = useRef(null);
const handleSubmit = (event) => {
event.preventDefault();
alert(`The name entered was: ${inputRef.current.value}`);
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" ref={inputRef} />
</label>
<button type="submit">Submit</button>
</form>
);
}
export default SimpleUncontrolledForm;
Step-by-Step Code Breakdown:
import React, { useRef } from 'react';
: We import React and theuseRef
hook.const inputRef = useRef(null);
: We create a ref calledinputRef
and initialize it tonull
.<input type="text" ref={inputRef} />
: We attach theinputRef
to our input element using theref
attribute. React will set thecurrent
property of the ref to the corresponding DOM element.handleSubmit
: When the form is submitted, we access the input's value usinginputRef.current.value
.
2.2 - The defaultValue
Prop
With uncontrolled components, you can provide an initial value using the defaultValue
prop.
// code-block-2.jsx
<input type="text" ref={inputRef} defaultValue="John Doe" />
It's important to note that the defaultValue
prop only sets the initial value. Subsequent changes to the defaultValue
prop will not update the value in the DOM.
🛠️ Section 3: When to Use Uncontrolled Components
While controlled components are the standard for forms in React, there are some use cases where uncontrolled components are a good fit:
- Simple Forms: For very simple forms where you only need the value on submission, uncontrolled components can be less code.
- File Inputs: The
<input type="file" />
element is always uncontrolled because its value can only be set by a user for security reasons. - Integrating with Non-React Code: If you are integrating React with a library that manipulates the DOM directly (like a jQuery plugin), uncontrolled components can be easier to work with.
- Performance: In rare cases where the re-rendering of a controlled component is causing performance issues, an uncontrolled component might be a valid alternative.
🔬 Section 4: A Deeper Dive: Key Differences
Let's compare controlled and uncontrolled components side-by-side:
Feature | Controlled Components | Uncontrolled Components |
---|---|---|
Source of Truth | React state | The DOM |
Data Flow | State drives the value of the input | Refs are used to "pull" the value from the DOM |
Re-renders | Re-renders on every keystroke | Does not re-render when the input value changes |
Validation | Can be done in real-time as the user types | Typically done on submission |
Code Complexity | Can be more verbose for simple forms | Can be simpler for basic forms |
✨ Section 5: Best Practices and Anti-Patterns
Best Practices:
- Use controlled components by default: They provide more predictable state management and are easier to debug.
- Use uncontrolled components for specific use cases: File inputs, simple forms, and integration with non-React code are good candidates.
- Use
defaultValue
for initial values: This is the correct way to set an initial value for an uncontrolled component.
Anti-Patterns (What to Avoid):
- Mixing controlled and uncontrolled components for the same input: This can lead to unpredictable behavior and bugs.
- Overusing refs: While refs are powerful, they should be used sparingly. Overusing them can make your code harder to reason about and can be a sign that you should be using a controlled component instead.
💡 Conclusion & Key Takeaways
Congratulations! You now understand the difference between controlled and uncontrolled components and how to use the useRef
hook to manage uncontrolled form inputs.
Let's summarize the key takeaways:
- Uncontrolled components let the DOM manage the form data.
- The
useRef
hook is used to get a reference to the DOM element and access its value. - Uncontrolled components are a good choice for simple forms, file inputs, and integrating with non-React code.
Challenge Yourself: To solidify your understanding, try to build a form with a file input and a text input, using an uncontrolled approach for both.
➡️ Next Steps
You now have a complete understanding of the two main ways to handle forms in React. In the next article, "Form Validation: The Basics", we will explore different techniques for validating form data on the client-side.
Thank you for your dedication. Stay curious, and happy coding!
glossary
- Uncontrolled Component: A form element that maintains its own internal state, managed by the DOM.
useRef
: A React hook that lets you reference a DOM element.defaultValue
: A prop used to set the initial value of an uncontrolled component.