What is useRef?
The useRef Hook gives you a way to access DOM elements directly and persist values across renders without causing re-renders. It's like a sticky note that stays on your desk - you can write something on it, and it'll be there the next time you look. Unlike state, changing a ref doesn't trigger a re-render. It's perfect for storing values that need to persist but shouldn't affect what the component displays.
You'll often see useRef used for accessing input fields, managing focus, or storing timer IDs. It returns a mutable object with a current property. Whatever you put in current stays there until you change it or the component unmounts. Simple, powerful, and incredibly useful.
Accessing DOM Elements
One of the most common uses for useRef is accessing DOM elements. You pass a ref to a JSX element's ref attribute, and React sets the ref's current property to that DOM node. This is useful when you need to measure elements, manage focus, or integrate with non-React libraries.
function TextInput() {
const inputRef = useRef(null)
const focusInput = () => {
inputRef.current.focus()
}
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus Input</button>
</div>
)
}
Try it Yourself โ
Persisting Values Across Renders
Refs aren't just for DOM access - they're also great for storing values that need to persist across renders without causing re-renders. Think of things like previous state values, timer IDs, or any mutable value that doesn't need to trigger a visual update. The value stays the same between renders, unlike variables declared inside the component which get reset each time.
function Stopwatch() {
const [time, setTime] = useState(0)
const intervalRef = useRef(null)
const start = () => {
intervalRef.current = setInterval(() => {
setTime(t => t + 1)
}, 1000)
}
const stop = () => {
clearInterval(intervalRef.current)
}
return (
<div>
<p>{time}s</p>
<button onClick={start}>Start</button>
<button onClick={stop}>Stop</button>
</div>
)
}
Try it Yourself โ
useRef vs useState
The key difference between useRef and useState is re-renders. When you update state, the component re-renders with the new value. When you update a ref, nothing happens visually - the value changes silently. Use state for data that should be displayed in the UI. Use refs for values that need to persist but don't affect rendering.
A good rule of thumb: if changing the value should cause the component to update, use state. If it's just internal bookkeeping that the user doesn't need to see, use a ref. Mixing them up leads to bugs that are tricky to track down.