Skip to main content

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:

  1. import React, { useRef } from 'react';: We import React and the useRef hook.
  2. const inputRef = useRef(null);: We create a ref called inputRef and initialize it to null.
  3. <input type="text" ref={inputRef} />: We attach the inputRef to our input element using the ref attribute. React will set the current property of the ref to the corresponding DOM element.
  4. handleSubmit: When the form is submitted, we access the input's value using inputRef.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:

FeatureControlled ComponentsUncontrolled Components
Source of TruthReact stateThe DOM
Data FlowState drives the value of the inputRefs are used to "pull" the value from the DOM
Re-rendersRe-renders on every keystrokeDoes not re-render when the input value changes
ValidationCan be done in real-time as the user typesTypically done on submission
Code ComplexityCan be more verbose for simple formsCan 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.

Further Reading