React
medium
mid
What are useRef and forwardRef in React and when do you use them?
`useRef` returns a mutable container that survives renders without triggering them. `forwardRef` lets a parent's ref reach a child's DOM node. Use refs for imperative DOM access and persistent values; never as state replacements.
5 min read·~10 min to think through
Two related but distinct primitives.
useRef(initial) returns an object { current } that:
- Persists across renders (like state).
- Mutating
.currentdoes not trigger a re-render (unlike state). - Is the canonical way to "remember" something between renders that the UI doesn't directly reflect — DOM nodes, timer ids, latest props for use inside a stable callback.
Two main use cases:
- DOM access —
<input ref={ref} />thenref.current.focus(). - Mutable scratchpad — interval ids, previous values, "is mounted" flags, latest-prop refs to break stale closures.
forwardRef lets a function component receive a ref and forward it to a DOM child. Without it, <Input ref={r} /> wouldn't work because function components don't have refs by default.
In React 19, ref is just a regular prop on function components — forwardRef is no longer required. But the codebase you walk into in 2026 still uses it, so know both.
Code
tsx
function Stopwatch() {
const start = useRef<number>(performance.now()); // mutable, no rerender
const [elapsed, setElapsed] = useState(0);
useEffect(() => {
const id = setInterval(() => setElapsed(performance.now() - start.current), 100);
return () => clearInterval(id);
}, []);
return <span>{elapsed.toFixed(0)}ms</span>;
}tsx
const Input = forwardRef<HTMLInputElement, InputProps>(
function Input(props, ref) {
return <input ref={ref} {...props} className="..." />;
},
);
// Parent
const ref = useRef<HTMLInputElement>(null);
<Input ref={ref} />;
ref.current?.focus();Follow-up questions
- •What's the difference between useRef and createRef?
- •When is the latest-prop ref pattern needed?
- •How does React 19 simplify forwardRef?
Common mistakes
- •Using a ref to drive UI — UI must come from state, not refs.
- •Reading `ref.current` during render — it may be null on first render.
- •Putting a ref on an array of children without keys + per-item refs.
Performance considerations
- •Refs avoid re-renders, useful for high-frequency values (mouse position) where you only need DOM mutation, not React state.
Edge cases
- •Callback refs (`ref={(el) => …}`) run on mount/unmount with the node and null — useful when you need to attach an observer.
- •Strict Mode mounts twice in dev; ref cleanup must be idempotent.
Real-world examples
- •Floating-UI uses callback refs to attach a ResizeObserver and re-position on layout changes.
Senior engineer discussion
Senior signal: discuss imperative-handle (`useImperativeHandle`), the latest-prop pattern for stable callbacks, and how React 19 unifies refs as regular props.