refs
useRef
Returns a mutable object whose .current property persists for the lifetime of the component without triggering re-renders on change. Reach for it to hold DOM nodes, timers, previous values, or any imperative handle that render output does not depend on.
const ref = useRef(initialValue) Parameters & Behavior
| Parameter | Purpose |
|---|---|
| initialValue | Value assigned to ref.current on the first render |
| ref.current | Read/write slot — mutating it does NOT re-render the component |
| <div ref={ref}> | React assigns the DOM node to ref.current after commit |
| stable identity | The ref object itself is stable across renders, safe as a dep or callback capture |
Examples
const inputRef = useRef(null);
useEffect(() => { inputRef.current?.focus(); }, []);
return <input ref={inputRef} />; Focus a DOM node imperatively on mount
const timerRef = useRef(null);
timerRef.current = setTimeout(fn, 1000);
return () => clearTimeout(timerRef.current); Hold a timer handle without causing re-renders
const prev = useRef(value);
useEffect(() => { prev.current = value; });
const prevValue = prev.current; Track the previous value of a prop or state
const renderCount = useRef(0);
renderCount.current++; Count renders for debugging without triggering more renders
Gotcha
Reading ref.current during render is generally unsafe — the DOM ref isn't populated until after commit, and mutating a ref during render can cause tearing. Use state, not refs, for values that the UI must reflect.
Related hooks
useImperativeHandle
Customizes the value a parent gets when it attaches a ref to your component, exposing only a curated imperative API. Reach for it when a parent legitimately needs to call methods like focus(), scrollTo(), or play() on a child.
useState
Declares a piece of local state in a function component and returns the current value along with a setter. Reach for it whenever a component needs to remember a value across renders and re-render when that value changes.
useLayoutEffect
Runs a side effect synchronously after DOM mutations but before the browser paints. Reach for it only when you need to measure the DOM and then mutate it in a way the user must never see mid-flight (e.g. tooltip positioning).