What are Refs?
Most React data flows through props and state. A ref is different: it is a way to keep a direct reference to something without causing a render.
Refs are commonly used for:
- accessing a DOM node, such as an input or video element
- storing a mutable value that should survive renders
- exposing a small imperative API from a child component
- integrating with browser APIs or third-party libraries that need a DOM element
Refs are powerful, but they are not a replacement for state.
Declarative First
React prefers declarative code.
Instead of saying "find this DOM node and change its text", you usually say "render this text from state".
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}The button label changes because state changes. No manual DOM update is needed.
Use a ref when the thing you need is outside normal rendering.
function SearchBox() {
const inputRef = useRef(null);
function focusSearch() {
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} />
<button onClick={focusSearch}>Focus search</button>
</>
);
}Here, focusing is an imperative browser action. A ref is appropriate.
What a Ref Looks Like
A ref object has a current property.
const inputRef = useRef(null);React sets inputRef.current to the DOM element after the component is rendered.
Before the element exists, current is null.
After the element is removed, React sets it back to null.
Refs Do Not Trigger Renders
Changing a ref does not re-render the component.
function RenderCount() {
const renderCount = useRef(0);
renderCount.current += 1;
return <p>Rendered {renderCount.current} times</p>;
}This works because the ref value survives between renders.
But if the user interface must update when a value changes, use state instead.
function BadCounter() {
const countRef = useRef(0);
return (
<button onClick={() => countRef.current += 1}>
Count: {countRef.current}
</button>
);
}Clicking the button changes the ref, but React does not know it needs to render again. The displayed count will not reliably update.
Common Ref Use Cases
Refs are useful when you need to:
- focus an input after an action
- scroll an element into view
- measure an element size
- control media playback
- store a timer ID
- store a previous value
- connect a chart, map, or editor library to a DOM node
function VideoPlayer() {
const videoRef = useRef(null);
return (
<>
<video ref={videoRef} src="/intro.mp4" />
<button onClick={() => videoRef.current.play()}>Play</button>
<button onClick={() => videoRef.current.pause()}>Pause</button>
</>
);
}Avoid Using Refs for Normal Data Flow
If a parent needs to affect a child, prefer props.
If a child needs to notify a parent, prefer callback props.
If the UI depends on a value, prefer state.
Refs should usually be the exception, not the default.
Safe Access
Because refs can be null, check before using them when timing is uncertain.
function scrollToResult(resultRef) {
if (!resultRef.current) {
return;
}
resultRef.current.scrollIntoView({ behavior: "smooth" });
}Inside event handlers after the element is mounted, the ref is usually available. In effects, it is still a good habit to think about cleanup and conditional rendering.
Common Mistakes
- Storing visible UI data in refs instead of state.
- Reading
ref.currentduring render to decide what to display. - Mutating DOM styles directly when class names or props would be clearer.
- Forgetting that
currentmay benull. - Passing a ref to a function component that does not forward it.
Awareness Note: Strict Mode
In development, React Strict Mode may run some render and effect logic more than once to help find unsafe code.
Do not write ref logic that depends on effects running exactly once. Always make setup and cleanup predictable.
Which statement best describes a React ref?
Recap
Refs let React components hold references to DOM nodes or mutable values.
Use refs for imperative actions and integration points. Use state and props for data that should drive the rendered output.
Practice
Build a small form with a search input and a "Focus search" button.
Then add a second button that clears the input by updating React state, not by directly mutating the DOM value.