Quiz

What is the `useRef` hook in React and when should it be used?

Topics
React

TL;DR

The useRef hook in React is used to create a mutable object that persists across renders. It can be used to access and manipulate DOM elements directly, store mutable values that do not cause re-renders when updated, and keep a reference to a value without triggering a re-render. For example, you can use useRef to focus an input element:

import React, { useRef, useEffect } from 'react';
function TextInputWithFocusButton() {
const inputEl = useRef(null);
useEffect(() => {
inputEl.current?.focus();
}, []);
return <input ref={inputEl} type="text" />;
}

What is the useRef hook in React and when should it be used?

Introduction to useRef

The useRef hook in React is a function that returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component. Updating ref.current does not trigger a re-render.

A few important rules:

  • Do not read or write ref.current during rendering. React only guarantees the ref's value is settled after commit; mutating it during render makes components impure and is disallowed.
  • It is fine (and expected) to read or write ref.current inside event handlers, effects, or callbacks.

Key use cases for useRef

Accessing and manipulating DOM elements

One of the primary use cases for useRef is to directly access and manipulate DOM elements. This is particularly useful when you need to interact with the DOM in ways that are not easily achievable through React's declarative approach.

Example:

import React, { useRef, useEffect } from 'react';
function TextInputWithFocusButton() {
const inputEl = useRef(null);
useEffect(() => {
inputEl.current?.focus();
}, []);
return <input ref={inputEl} type="text" />;
}

In this example, the useRef hook is used to create a reference to the input element, and the useEffect hook is used to focus the input element when the component mounts. The optional chaining (?.) guards against the rare case where the element is not yet attached, which is a good habit under React 19's stricter dev-mode checks.

Storing mutable values across renders

useRef can also be used to store any mutable value that should persist across renders without causing one. Common examples are interval/timeout IDs, the previous value of a prop or state, an instance of a non-React object (e.g. a chart or map controller), or a counter used inside event handlers.

import React, { useRef, useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
const prevCountRef = useRef(undefined);
useEffect(() => {
prevCountRef.current = count;
}, [count]);
return (
<div>
<h1>Now: {count}</h1>
<h2>Before: {prevCountRef.current}</h2>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

Here prevCountRef holds the previous value of count across renders, but updating it does not itself cause a re-render.

Refs in React 19

React 19 changed how refs interoperate with components in two important ways:

ref is now a regular prop — forwardRef is deprecated

In function components, ref is now an ordinary prop. You can accept it directly in your props and pass it to a DOM node (or to another component) without wrapping the component in React.forwardRef. forwardRef still works but is deprecated and scheduled for removal in a future major.

// React 19+: just accept `ref` as a prop.
function FancyInput({ ref, ...props }) {
return <input ref={ref} {...props} />;
}
// Usage is unchanged at the call site:
function Parent() {
const inputRef = useRef(null);
return <FancyInput ref={inputRef} placeholder="Type..." />;
}

Cleanup functions from ref callbacks

Ref callbacks may now return a cleanup function, which React runs when the ref detaches (similar to useEffect). This removes the need for the older "called with null" pattern.

<input
ref={(node) => {
node.focus();
return () => {
// runs when the element unmounts or the ref changes
};
}}
/>

Further reading

Edit on GitHub