A ref is a mutable box that survives renders and does not participate in them, which is the right shape for a timer id, a previous value or an interaction flag.
const timer = useRef(null)
const hasInteracted = useRef(false)
function start() {
timer.current = setInterval(tick, 1000) // no re-render
}
// and the trap: reading a ref during render is not
// reactive, so this never updates the output
return <p>{hasInteracted.current ? 'yes' : 'no'}</p>
Using state for a timer id causes a render on every start and stop, which is pure waste and occasionally an infinite loop. The corresponding mistake in the other direction is reading a ref in the returned markup and expecting the display to follow it — the value is current and nothing re-rendered, so the screen shows whatever the last real render produced. If it appears in the output, it is state.