π£ 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
useRefhook is and how it works - How to use
useReffor 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.currentholds a mutable value- Unlike state, updating
myRef.currentdoes 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
useReffor 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 :
