Callback Refs vs Object Refs in React

Object refs hold a node in a current property, while callback refs run a function whenever a node attaches or detaches. Learn which fits your case.

6 min read

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 refCallback ref
ShapeAn object with a current propertyA function
When it updatesReact sets current during commitReact calls it with the node on attach
On detachReact sets current to nullReact calls it with null
Best forHolding one nodeReacting 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.

App.jsxApp.jsx
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.

App.jsxApp.jsx
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.

App.jsxApp.jsx
<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

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.
RunePowered by Rune AI

Frequently Asked Questions

What is the difference between a callback ref and an object ref?

An object ref stores a node in current, while a callback ref is a function React calls with the node on attach and with null on detach.

Do callback refs run twice in Strict Mode?

Yes, in development React calls callback refs twice with an attach and detach cycle, so the returned cleanup must be idempotent.

When should I use a callback ref?

Use one when you must react to attach or detach, or when you need a ref for every item in a dynamic list.

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.