What is a ref?
useRef creates an object { current: ... } that persists between
renders and that you can mutate freely. The distinctive part: changing
ref.current does NOT trigger a re-render. It's the opposite of useState.
const ref = useRef(initialValue);
ref.current; // read the value
ref.current = other; // change it (without re-rendering)
It has two main uses.
1) Referencing a DOM node
By passing a ref to the ref attribute of an element, React puts the real DOM
node into ref.current. This lets you do imperative things like focusing an
input:
function SearchBox() {
const inputRef = useRef(null);
return (
<div>
<input ref={inputRef} placeholder="Search…" />
<button onClick={() => inputRef.current.focus()}>Focus</button>
</div>
);
}
When the component mounts, inputRef.current points to the real <input>, and
we can call .focus(), .scrollIntoView(), etc.
2) Storing a mutable value that does NOT re-render
Sometimes you need to remember a piece of data between renders but you don't
want changing it to re-render the interface: the id of a setInterval, the
previous value of a prop, an internal counter... That goes in a ref, not in
state.
function Render() {
const renders = useRef(0);
renders.current++; // counts renders WITHOUT triggering another render
return <p>Renders: {renders.current}</p>;
}
State vs. ref
useState |
useRef |
|
|---|---|---|
| On value change | re-renders | does not re-render |
| What for | data shown in the UI | DOM and "behind the scenes" values |
| How to change it | with setX(...) |
mutating ref.current |
Practical rule: if the data is shown and must appear updated, it goes in state. If it's an internal detail the UI doesn't need to display on change, it goes in a ref. Want to show a ref's value on screen? Copy it to state at the right moment (e.g., when pressing a button).