useRef Hook
In this page:
const refName = useRef(initialValue);
<element ref={refName} />
// Read or write without re-rendering
refName.current;
Accessing a DOM Element with useRef
Passing a ref object to an element's ref prop gives you direct access to the actual DOM node once it's rendered, available at ref.current. This is useful for things React doesn't have a built-in prop for, like focusing an input programmatically.
ref.current for a DOM element is only populated AFTER the component renders -- access it inside an event handler or useEffect, not during render.ref.current directly in the render body (not inside an effect or handler) will be null on the first render, before the DOM exists.Example: Accessing a DOM Element with useRef
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function FocusInput() {
const inputRef = React.useRef(null);
return (
<div>
<input ref={inputRef} placeholder="Click button to focus me" />
<button onClick={() => inputRef.current.focus()}>Focus Input</button>
</div>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<FocusInput />);
</script>
</body>
</html>
Storing a Mutable Value Without Re-rendering
Unlike state, updating a ref's .current value does not cause the component to re-render. This makes refs ideal for storing values you need to keep track of, like a timer ID or a previous value, without triggering unnecessary UI updates.
Example: Storing a Mutable Value Without Re-rendering
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function ClickCounter() {
const clicksRef = React.useRef(0);
function handleClick() {
clicksRef.current += 1;
console.log("Clicked", clicksRef.current, "times (check console, no re-render)");
}
return <button onClick={handleClick}>Click me (see console)</button>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<ClickCounter />);
</script>
</body>
</html>
useRef vs useState
Both persist a value across renders, but they serve very different purposes: state changes should be visible in the UI and trigger a re-render, while ref changes are typically 'behind the scenes' bookkeeping that shouldn't affect what's displayed.
Choosing the right one avoids both unnecessary re-renders and missing UI updates.
- Ask: 'should the screen update when this value changes?'
- If yes, use state.
- If no, use a ref.
Example: useRef vs useState
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function Comparison() {
const [stateValue, setStateValue] = React.useState(0);
const refValue = React.useRef(0);
return (
<div>
<p>State (updates UI): {stateValue}</p>
<button onClick={() => setStateValue(stateValue + 1)}>Update State</button>
<button onClick={() => { refValue.current += 1; console.log("Ref is now", refValue.current); }}>Update Ref (check console)</button>
</div>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<Comparison />);
</script>
</body>
</html>
- Expecting a change to a ref's
.currentvalue to trigger a re-render -- it never does. - Reading
ref.currentduring the render itself for a DOM element ref, before the DOM has actually been created. - Confusing useRef with useState -- refs are for values that don't need to cause re-renders, state is for values that do.
- useRef returns a mutable object with a single
.currentproperty. - Changing
.currentdoes NOT trigger a re-render, unlike state. - A common use is accessing a DOM element directly, via the
refprop. - Another common use is storing a mutable value that persists across renders without causing updates.
Available since React 16.8, when Hooks were introduced.
Chapter Quiz — Complete all 12 topics to unlock
0/12 topics done
Complete these topics first: