Lesson 10 of 80
A mutable box that survives between renders, exactly like useState — except changing it never triggers a re-render. That one difference is the whole lesson.
13 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 2
Does calling `myRef.current = 5` trigger a re-render, the way `setState(5)` would?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
useRef(initialValue) returns a plain object: { current: initialValue }. That object is the same object across every render of the component — React doesn't recreate it. You can read and write .current freely, and it behaves nothing like state:
function Stopwatch() {
const intervalId = useRef(null); // survives renders, mutating it doesn't re-render
const [running, setRunning] = useState(false);
function start() {
intervalId.current = setInterval(() => console.log("tick"), 1000);
setRunning(true);
}
function stop() {
clearInterval(intervalId.current);
setRunning(false);
}
// ...
}
intervalId needs to survive between renders (so stop can clear the same interval start created) but has no business triggering a re-render when it changes — nothing on screen depends on its value. That's exactly what useRef is for; useState would work but would cause pointless extra renders.
const ref = useRef(initialValue) — a mutable box that persists across renders.
.current during render is a footgun. Refs are meant for effects and event handlers, which run after render — mutating a ref during render can silently produce a value that's one render behind, since the read doesn't trigger a re-render to reconcile it.setInterval callback) without wanting a re-render on every tick.ref.current starts as null for DOM refs until after the first render commits — accessing inputRef.current.focus() during the render itself, before the DOM exists, throws."When would you use useRef instead of useState?" is a direct test of whether you understand why two hooks that both "hold a value across renders" exist — the answer is entirely about whether a change should cause a re-render.