Updated June 2026. Tested on React 19 and modern JavaScript. Part of the Techalyst React series.

useRef looks like it does two unrelated things: it grabs DOM elements, and it stores a value that does not cause re-renders. They are actually the same idea wearing two hats. A ref is a little box, ref.current, that React keeps for you across renders and never reacts to. Once you see it that way, both uses make sense.

Reaching a DOM node

The common use is getting a real element so you can focus it, measure it, or scroll it. You create a ref, attach it with the ref attribute, and after the component mounts ref.current is the DOM node:

function SearchBox() {
  const inputRef = useRef(null);

  useEffect(() => {
    inputRef.current.focus(); // focus on mount
  }, []);

  return <input ref={inputRef} />;
}

The ref is null until the element is on screen, so you read it in an effect or an event handler, not during render where the node does not exist yet. This is the React equivalent of grabbing an element to work with it imperatively, for the few cases where you genuinely need the node.

Holding a value without re-rendering

The second use is the one people miss. A ref can hold any value, and changing ref.current does not trigger a re-render. That makes it the right place for data you want to remember between renders but that should not affect what is on screen: a timer id, the previous value of something, a flag that you are mid-request.

const intervalRef = useRef(null);

function start() {
  intervalRef.current = setInterval(tick, 1000);
}

function stop() {
  clearInterval(intervalRef.current);
}

If you stored that interval id in state instead, every start would re-render for no visual reason. A ref keeps it around quietly.

Ref versus state, the real distinction

This is the decision that matters. Both survive across renders, but they differ in one way: changing state re-renders the component, changing a ref does not. So the question is simply whether this value should update the UI.

If the value appears on screen, it is state. If it is bookkeeping the user never sees directly, a ref is lighter and avoids needless renders. Put a counter the user reads in state. Put the id of the timer driving that counter in a ref.

Do not read or write refs during render

One rule keeps refs predictable: do not touch ref.current while rendering. Reading a DOM ref during render gives you stale or null values, and writing to a ref during render is a side effect that makes your component impure. Keep ref access inside effects and event handlers, where the timing is defined.

Passing a ref to a child

In React 19 a ref is just a regular prop, so a component can accept one and forward it to an element without the old forwardRef wrapper. If you have a custom TextInput and want the parent to focus it, the parent passes a ref and the child attaches it to its <input>. This is the parallel of grabbing a child's element, done the React way.

Wrapping up

useRef gives you a stable box, ref.current, that persists across renders and never causes one. Use it to reach DOM nodes for focusing, measuring, or scrolling, reading it in effects rather than during render. Use it to hold mutable bookkeeping, like a timer id or a previous value, that should not re-render the UI. The deciding question between a ref and state is always the same: does this value belong on screen? If yes, state. If no, a ref.