π£ React useRef
Hook β DOM Access & Mutable Refs (2025 Guide)
π§² Introduction β Why Use useRef
?
In React.js, most data changes should flow through state and props. However, sometimes you need to interact with DOM elements directly or store values that persist across renders without causing re-renders. Thatβs where the useRef
hook comes in.
The useRef
hook gives you a mutable object whose .current
property persists across re-renders β perfect for working with the DOM, timeouts, scroll positions, form focus, and more.
π― In this guide, youβll learn:
- What the
useRef
hook is and how it works - How to use
useRef
for DOM access and value persistence - Real-world examples and common use cases
- Best practices and pitfalls to avoid
π§© What is the useRef
Hook?
useRef
is a React Hook that returns a ref object:
const myRef = useRef(initialValue);
myRef.current
holds a mutable value- Unlike state, updating
myRef.current
does NOT trigger a re-render
π§± 1. Accessing DOM Elements with useRef
React assigns the ref to the current
property once the DOM is rendered.
β Example β Focusing an Input:
import { useRef } from 'react';
function FocusInput() {
const inputRef = useRef();
const handleClick = () => {
inputRef.current.focus();
};
return (
<>
<input ref={inputRef} type="text" placeholder="Click the button to focus" />
<button onClick={handleClick}>Focus Input</button>
</>
);
}
π ref={inputRef}
attaches the reference to the DOM element
β
Great for managing focus, selection, or scroll behavior
π 2. Persisting Values Without Re-Rendering
Sometimes you need to persist a value between renders without re-rendering when it changes.
β Example β Store Previous Value:
import { useEffect, useRef, useState } from 'react';
function PreviousCounter() {
const [count, setCount] = useState(0);
const prevCountRef = useRef();
useEffect(() => {
prevCountRef.current = count;
});
return (
<>
<p>Now: {count}, Before: {prevCountRef.current}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</>
);
}
β
prevCountRef.current
updates after each render
β
But the update itself doesnβt trigger a new render
π§ͺ 3. useRef
vs useState
Feature | useRef | useState |
---|---|---|
Triggers re-render | β No | β Yes |
Mutable storage | β
Yes (ref.current ) | β
Yes (setState ) |
DOM access | β Common use case | β Not for DOM |
Async-safe persistence | β Good for setInterval, timers | β οΈ Requires useEffect or memo |
π 4. Using useRef
for Timers and Intervals
β Example β Clear an Interval:
function Timer() {
const timerRef = useRef();
const startTimer = () => {
timerRef.current = setInterval(() => {
console.log('Tick');
}, 1000);
};
const stopTimer = () => {
clearInterval(timerRef.current);
};
return (
<>
<button onClick={startTimer}>Start</button>
<button onClick={stopTimer}>Stop</button>
</>
);
}
β
useRef
stores interval IDs without rerenders
π§± 5. Forwarding Refs to Child Components
Sometimes you want to expose a ref from a child component to a parent.
β Example:
const MyInput = React.forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
function App() {
const inputRef = useRef();
return <MyInput ref={inputRef} />;
}
π Use forwardRef
to allow parent access to child DOM nodes
β οΈ 6. Common Pitfalls
Mistake | Fix |
---|---|
Expecting re-render on .current update | Use useState instead |
Using ref without ref.current check | Always check before accessing DOM |
Misunderstanding its async behavior | Remember refs persist across renders |
π Best Practices
β
Use useRef
to:
- Focus or scroll to DOM elements
- Store mutable values like timers or counters
- Avoid triggering renders with frequent changes
β Don’t use useRef
when you need to reflect changes in the UI β use useState
instead
π Summary β Recap & Next Steps
The useRef
hook is the Swiss Army knife for handling DOM nodes and persistent mutable values in React. Itβs especially useful for accessing elements, tracking values between renders, and managing imperatively controlled behaviors like focus and timers.
π Key Takeaways:
useRef()
returns a mutable ref object- Use it to access DOM nodes with
ref={...}
- Useful for storing values across renders without causing re-renders
- Combine with
useEffect()
for lifecycle-driven logic - Avoid using
useRef
for state that needs to update the UI
βοΈ Real-World Relevance:
Used in forms, modals, animations, timers, and integrations where you need direct DOM access or non-reactive persistence (e.g., debounce, scroll tracking).
β FAQ Section
β Does updating a ref with useRef
re-render the component?
β No. Thatβs one of the key benefits β useRef
stores mutable data without triggering renders.
β When should I use useRef
over useState
?
β
Use useRef
when:
- You want to avoid re-renders
- You need to access the DOM directly
- You need to store a value across renders (e.g., previous value, timeout ID)
β Can I use useRef
to focus an input?
β
Yes! Simply attach it to the ref
prop and call ref.current.focus()
.
β What is .current
in useRef
?
β
.current
is the actual value or DOM node held by the ref object.
β Can I use useRef
with custom components?
β
Yes, but only if that component uses forwardRef
internally.
Share Now :