Skip to content

useRef & the DOM

useRef gives you a mutable container — an object { current: value } — that React keeps across renders but does not watch. Changing ref.current does not trigger a re-render.

const ref = useRef(0);
ref.current += 1; // mutate freely — NO re-render happens

That’s the whole difference from state:

useStateuseRef
Survives re-renders
Changing it re-renders✅ yes❌ no
Read during render✅ (it’s the snapshot)⚠️ avoid (mutable, not reactive)
Use fordata shown in the UIvalues you need to remember but not render

Use a ref for things the UI doesn’t directly display: a timer id, the previous value of something, a mutable counter, a scroll position, or a reference to a DOM node.

// Classic use: hold a timer id so you can clear it later.
const intervalRef = useRef(null);
function start() {
intervalRef.current = setInterval(tick, 1000);
}
function stop() {
clearInterval(intervalRef.current);
}

The most common use is grabbing a DOM node — to focus an input, measure an element, or call an imperative browser API. Attach the ref to a host element via the ref attribute; after commit, ref.current points at the real DOM node.

function SearchBox() {
const inputRef = useRef(null);
return (
<>
<input ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>Focus</button>
</>
);
}

This is an escape hatch — you’re stepping outside the declarative model to talk to the DOM directly. Use it for focus, scrolling, measurements, and integrating non-React widgets; don’t use it to do things state can do.

Previously, passing a ref through your own component to a DOM node inside it required wrapping the component in forwardRef. In React 19, ref is a regular prop — you can accept it and pass it down like any other prop, and forwardRef is no longer needed for new code.

// ✅ React 19: accept ref as a normal prop — no forwardRef.
function MyInput({ placeholder, ref }) {
return <input placeholder={placeholder} ref={ref} />;
}
// Parent:
const ref = useRef(null);
<MyInput ref={ref} placeholder="Search" />;

The old form still works — forwardRef is not removed — but it’s now legacy. New components should take ref as a prop.

For the rarer case where you want to expose a custom imperative API (not the raw DOM node) to a parent, useImperativeHandle lets you define exactly what the ref exposes:

function FancyInput({ ref }) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => ({
focus: () => inputRef.current.focus(),
clear: () => { inputRef.current.value = ''; },
}));
return <input ref={inputRef} />;
}
What is the key difference between useRef and useState?
What is a good use for a ref?
In React 19, how do you pass a ref through your own component to an inner DOM node?
What does useImperativeHandle do?