Understanding React Refs in React
This article provides a clear and concise guide to React Refs,
explaining what they are, why they are used, and how to implement them
in your projects. You will learn the fundamental differences between
React state and refs, explore practical code examples using the
useRef hook to interact directly with the DOM, and
understand the best practices for using them safely in functional
components.
What is a React Ref?
A Ref (short for reference) is a built-in React feature that allows you to persist values between renders without triggering a re-render when the value changes. Additionally, refs provide a way to directly access and interact with actual HTML DOM nodes created in the render method.
While React typically handles DOM updates automatically through its declarative state paradigm, refs act as an escape hatch for cases where you need to imperatively modify the DOM.
Common Use Cases for Refs
You should not use refs for anything that can be done declaratively. However, refs are highly useful for the following scenarios:
- Managing Focus, Text Selection, or Media Playback: Automatically focusing an input field when a page loads, selecting text, or controlling video/audio elements.
- Triggering Imperative Animations: Controlling animations that require direct DOM manipulation.
- Integrating with Third-Party DOM Libraries: Interfacing with non-React libraries (such as D3.js or jQuery plugins) that need access to real DOM elements.
- Storing Timer IDs or Previous Values: Keeping track
of
setIntervalorsetTimeoutIDs, or storing data that needs to be preserved across renders without affecting the visual output.
How to Use Refs with the
useRef Hook
In modern React functional components, you declare a ref using the
useRef hook. This hook returns a mutable ref object with a
single property called current.
Here is a practical example of using a ref to focus an input element:
import React, { useRef } from 'react';
function FocusInput() {
// 1. Initialize the ref with a default value of null
const inputRef = useRef(null);
const handleClick = () => {
// 3. Access the DOM node via inputRef.current and call focus()
inputRef.current.focus();
};
return (
<div>
{/* 2. Attach the ref to the DOM element using the ref attribute */}
<input ref={inputRef} type="text" placeholder="Click button to focus me" />
<button onClick={handleClick}>Focus the Input</button>
</div>
);
}
export default FocusInput;In this example, useRef(null) creates a ref object. By
passing this object to the <input> element’s
ref attribute, React automatically assigns the
corresponding DOM element to inputRef.current once the
component mounts.
Key Differences: Refs vs. State
Understanding when to use state versus when to use refs is crucial for writing efficient React applications:
| Feature | React State | React Refs |
|---|---|---|
| Re-renders | Updating state triggers a component re-render. | Updating a ref does not trigger a re-render. |
| Usage | Used for values that are rendered on the screen. | Used for values not used in rendering (DOM nodes, timers). |
| Access | Updated asynchronously via a setter function. | Updated synchronously by modifying the
current property directly. |
Best Practices for Using Refs
To maintain clean and predictable code, keep these rules in mind when working with refs:
- Do not read or write
ref.currentduring rendering: React expects rendering to be a pure function. Reading or writing toref.currentduring the render phase can lead to unpredictable behavior. Only read or write to refs inside event handlers or theuseEffecthook. - Keep it local: Avoid passing refs deeply down the
component tree. If a parent component needs access to a child’s DOM
node, use the
forwardRefAPI. - Avoid overusing refs: Do not use refs to bypass React’s data-flow model. If a value can be computed or stored in state, prefer state over refs.