useRef: refs & the DOM
Focus inputs, measure elements, store mutable values without re-rendering, and ref as a prop in React 19.
Sometimes a component needs to remember something without re-rendering, or to reach directly into the DOM — focus an input, scroll to an element, measure its size, play a video. That's what refs are for. useRef gives you a mutable box that persists across renders and that React doesn't watch.
useRef basics#
useRef(initialValue) returns an object { current: initialValue }. React gives you the same object on every render, so whatever you store in current survives re-renders — but changing it doesn't trigger one.
Refs vs state
If the value affects what the user sees, use state. If it's bookkeeping that the JSX doesn't depend on, a ref is fine.
Accessing DOM elements#
Pass a ref object to an element's ref attribute, and React puts the DOM node in ref.current:
The node is assigned after React creates it, so inputRef.current is null during the first render. Read it in event handlers or effects, not in the render body.
Focusing on mount
(For simple cases the autoFocus attribute does the same; refs give you control over when to focus.)
Scrolling an element into view
Measuring elements
useLayoutEffect measures before the browser paints, so there's no visible flicker. For sizes that change over time, use a ResizeObserver inside an effect.
Controlling media and third-party widgets
Refs are also how you hand a DOM node to a non-React library (a chart, a map) inside an effect.
Storing values that aren't rendered#
Timer ids
The interval id is needed by stop, but it's never displayed — perfect for a ref. (Displayed values, startTime and now, are state.)
Previous values and "latest" values
A "latest ref" lets a long-lived callback (an interval or subscription) read the newest props without re-subscribing.
Refs to your own components (React 19)#
In React 19, function components receive ref as a regular prop, so passing a ref through your own component is simple:
In older code you'll see forwardRef((props, ref) => ...), which was required before React 19 and is now unnecessary for new components.
Ref callbacks
Instead of a ref object, ref can take a function. React calls it with the node when it's attached; in React 19 it can return a cleanup function, called when the node is removed:
Ref callbacks are handy for lists, where you can't call useRef per item.
Exposing a custom handle
useImperativeHandle lets a component expose specific methods instead of its whole DOM node:
Use this sparingly — props and state are usually the better API.
Rules for refs#
- Don't read or write
ref.currentduring rendering (except to lazily initialise it). It makes rendering unpredictable. Do it in handlers and effects. - Prefer declarative props over imperative DOM calls. Use refs for things React can't express: focus, scroll, measurement, media playback, third-party DOM libraries.
- Don't manually change DOM that React manages (e.g. removing children React rendered) — React will get confused. Modifying things React doesn't control, like focus or scroll position, is fine.
Common mistakes#
- Using a ref for something displayed on screen, then wondering why the UI doesn't update.
- Reading
ref.currentduring the first render and gettingnull. - Calling
useRefinside a loop or condition (it's a hook — top level only). Use a ref callback or aMapin one ref for lists. - Using
document.querySelectorinside components instead of refs — it can find the wrong element if a component is rendered more than once.
What's next#
Next, share values across many components without passing props through every level: context.
Check your understanding
Quick quiz
1.What happens when you change
ref.current?2.When is
inputRef.currentset to the DOM node for<input ref={inputRef} />?3.In React 19, how can your own
TextInputcomponent accept arefand pass it to its inner<input>?
Finished reading?
Mark this lesson complete to track your progress.