import { useRef } from "react";
function SearchBox() {
const inputRef = useRef(null);
function focusInput() {
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} />
<button onClick={focusInput}>Focus</button>
</>
);
}The ref attribute connects inputRef.current directly to the real DOM <input> element, giving access to native browser methods like .focus() that React itself doesn't expose through props.
const [count, setCount] = useState(0); // updating this RE-RENDERS the component
const renderCount = useRef(0); // updating this does NOT re-render
renderCount.current = renderCount.current + 1; // changes silently, no re-render triggeredBoth hold a value across renders, but useState updates trigger a re-render while useRef updates don't. Use state for anything that should visibly update the UI; use a ref for values you need to track internally without affecting what's rendered โ like a timer ID or a previous value for comparison.
function Stopwatch() {
const [seconds, setSeconds] = useState(0);
const timerRef = useRef(null);
function start() {
timerRef.current = setInterval(() => setSeconds((s) => s + 1), 1000);
}
function stop() {
clearInterval(timerRef.current);
}
return (
<>
<p>{seconds}s</p>
<button onClick={start}>Start</button>
<button onClick={stop}>Stop</button>
</>
);
}Storing the timer's ID in a ref (rather than state) is exactly right here โ the ID itself never needs to be displayed on screen, it just needs to persist between the start and stop function calls.
If you store something in a ref that actually needs to be shown on screen, the UI simply won't update when it changes โ since ref updates don't trigger a re-render. If a value needs to visibly affect what's rendered, it belongs in useState, not useRef.
Build a component with an input and a button that, when clicked, selects (highlights) all the text currently in the input using a ref and the native .select() method.
import { useRef } from "react";
function SelectableInput() {
const inputRef = useRef(null);
return (
<>
<input ref={inputRef} defaultValue="Select me!" />
<button onClick={() => inputRef.current.select()}>Select All Text</button>
</>
);
}
Q Does changing a ref's .current value cause a re-render?
No โ this is the defining difference from useState. Changing ref.current is completely invisible to React's rendering system, which is exactly why refs are unsuitable for any value that needs to appear in the UI.
Q Can I use a ref instead of state just to avoid extra re-renders?
Only for values that genuinely never need to be displayed. If you store UI-relevant data in a ref to 'optimize' re-renders, the screen will simply fail to update correctly when that data changes โ a common and confusing beginner mistake.