A ref can be either an object with a current property or a function. Object refs are the common choice, while callback refs run your code whenever a node attaches or detaches. The difference is when and how often your code executes.
The two kinds of ref at a glance
| Object ref | Callback ref | |
|---|---|---|
| Shape | An object with a current property | A function |
| When it updates | React sets current during commit | React calls it with the node on attach |
| On detach | React sets current to null | React calls it with null |
| Best for | Holding one node | Reacting to attach or detach |
Both are escape hatches, and neither triggers a re-render on its own.
An object ref
Call useRef and attach the result to an element. React stores the DOM node in current.
import { useRef } from "react";
function SearchBox() {
const inputRef = useRef(null);
return (
<>
<input ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>Focus</button>
</>
);
}Clicking the button focuses the input. The object ref is the simplest way to keep one node around, and it is enough for most focus, scroll, and measure cases.
A callback ref
Pass a function instead. React calls it with the node after the element attaches, and with null when the element detaches.
import { useState } from "react";
function Box() {
const [width, setWidth] = useState(0);
return (
<div ref={(node) => node && setWidth(node.offsetWidth)} style={{ width: "50%" }}>
Width: {width}px
</div>
);
}When the div attaches, the callback records its width in state, and the box shows that width. The callback runs after commit, so the node exists and has layout.
Clean up in a callback ref
A callback ref can return a cleanup function. React calls it when the node detaches.
<li
ref={(node) => {
if (!node) return;
map.set(node.id, node);
return () => map.delete(node.id);
}}
/>Here map is a Map stored in a parent ref. Each item adds itself on attach and removes itself on detach, which keeps the map accurate for a changing list.
Strict Mode runs callbacks twice
In development, Strict Mode runs a callback ref once with the node, then once with null, then once with the node again. The cleanup must handle that repeated cycle without error. This is a stress test, not a production double render.
Which should you use?
Use an object ref when you need one stable node and plan to read it later. Use a callback ref when you must run logic the moment a node attaches or detaches, or when you need a ref for every item in a dynamic list. Both kinds still need a custom component to forward them, as covered in how to pass refs between components.
What to learn next
Passing refs down through custom components pairs with both kinds. Continue with how to integrate third-party DOM libraries.
Rune AI
Key Insights
- An object ref holds a node in current and updates during commit.
- A callback ref runs with the node on attach and with null on detach.
- Callback refs can return a cleanup function.
- Strict Mode runs callback refs twice in development.
- Use callback refs for dynamic lists and attach-time logic.
Frequently Asked Questions
What is the difference between a callback ref and an object ref?
Do callback refs run twice in Strict Mode?
When should I use a callback ref?
Conclusion
Object refs are the simple default for one node, while callback refs let you run code when a node attaches or detaches. Choose callback refs for dynamic lists and attach-time side effects.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.