React · Frontend system thinking
When should you use useRef instead of useState?
Short answer
Use useRef for a mutable value that should survive renders without causing one, such as a timer ID or previous value. Use useState when the UI must re-render in response to the change.
Both hooks preserve a value across renders. The difference is what happens when you change it. Setting state schedules a render and gives you a new value for that render. Mutating a ref changes the same object immediately and does not notify React.
function Stopwatch() {
const [elapsed, setElapsed] = useState(0);
const intervalRef = useRef(null);
function start() {
if (intervalRef.current !== null) return;
intervalRef.current = setInterval(() => {
setElapsed((current) => current + 1);
}, 1000);
}
function stop() {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
return (
<div>
<p>{elapsed}s</p>
<button onClick={start}>Start</button>
<button onClick={stop}>Stop</button>
</div>
);
}Good uses for a ref
- Timer, animation frame or request IDs
- A reference to a DOM node
- The previous value of a prop or state
- A value read by an event callback that should not re-subscribe
Do not use a ref to store something the UI displays. If the screen should change when the value changes, it is state. Do not read or write a ref during render to control behaviour either, because render must stay pure and may run more than once.
.current value is not a render snapshot. Reading it in an event handler gives you the current value; reading it during render can make the component's output depend on a mutation React did not track.Follow-ups you should expect
Interviewers use these to check whether the first answer was understanding or memorisation.
- 1Does changing a ref cause a re-render?
- 2Can you use a ref to store the previous value of a prop?
- 3Why shouldn't you read a ref during render?
- 4How is useRef different from a variable declared outside the component?
Say it in the interview
useRef gives me a stable container that survives renders without causing them. I use it for things React does not need to render, like timer IDs, DOM nodes or the previous value of a prop. useState is for data that affects the UI, because setting it schedules a render. I keep ref mutations out of render and use them in effects or event handlers.
Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.
Related questions
Reading is step one
Now say it out loud.
Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live React mock interview and get scored feedback on depth, clarity and confidence.