Recently, while working on a React project for a client in New York, I needed a way to access a DOM element directly without triggering a re-render. That’s when I turned to the useRef hook.
If you’ve ever used document.getElementById() in vanilla JavaScript, useRef gives you that same power, but in the React way. It’s simple, efficient, and helps keep your component performance smooth.
In this tutorial, I’ll show you how I use useRef in React functional components. We’ll look at two practical methods, one for accessing DOM elements and another for storing mutable values that persist across renders.
What is useRef in React?
The useRef hook is a part of React’s built-in Hooks API. It lets you create a reference to a value or DOM element that persists between renders, without causing the component to re-render when it changes.
Think of it as a “box” that holds a value. You can read or update what’s inside that box anytime, and React won’t re-render your component.
Here’s the basic syntax:
import React, { useRef } from 'react';
function MyComponent() {
const myRef = useRef(initialValue);
// myRef.current holds the value
}Method 1 – Use useRef to Access a DOM Element
One of the most common ways I use useRef is to directly manipulate or focus an input element, something you can’t easily do with state alone.
Let’s say you have a form where users enter their ZIP code, and you want to automatically focus the input field when the page loads.
Here’s how I do it:
Example: Focusing an Input Field Using useRef
import React, { useRef, useEffect } from 'react';
function ZipCodeForm() {
const inputRef = useRef(null);
useEffect(() => {
// Automatically focus the input when the component mounts
inputRef.current.focus();
}, []);
const handleSubmit = (e) => {
e.preventDefault();
alert(`ZIP Code entered: ${inputRef.current.value}`);
};
return (
<form onSubmit={handleSubmit} style={{ textAlign: 'center', marginTop: '50px' }}>
<label htmlFor="zipcode">Enter Your ZIP Code: </label>
<input
id="zipcode"
type="text"
ref={inputRef}
placeholder="e.g., 10001"
style={{ padding: '8px', marginRight: '10px' }}
/>
<button type="submit">Submit</button>
</form>
);
}
export default ZipCodeForm;I executed the above example code and added the screenshot below.

How it works:
- I first created a reference using useRef(null).
- Then, in the
useEffecthook, I calledinputRef.current.focus()to automatically focus the input field when the component mounts. - Since
useRefdoesn’t trigger re-renders, this approach is fast and efficient.
This is perfect for login forms, search boxes, or any place where you want to improve user experience.
Method 2 – Use useRef to Store Mutable Values
Another powerful use case for useRef is to store values that persist between renders, without causing re-renders.
For example, I once built a small timer app where I needed to store the setInterval ID. Using state for that would cause unnecessary re-renders, so I used useRef instead.
Example: Stopwatch Using useRef
import React, { useState, useRef } from 'react';
function Stopwatch() {
const [time, setTime] = useState(0);
const timerRef = useRef(null);
const startTimer = () => {
if (timerRef.current !== null) return; // Prevent multiple intervals
timerRef.current = setInterval(() => {
setTime((prevTime) => prevTime + 1);
}, 1000);
};
const stopTimer = () => {
clearInterval(timerRef.current);
timerRef.current = null;
};
const resetTimer = () => {
stopTimer();
setTime(0);
};
return (
<div style={{ textAlign: 'center', marginTop: '50px' }}>
<h2>Stopwatch</h2>
<h3>{time} seconds</h3>
<div>
<button onClick={startTimer}>Start</button>
<button onClick={stopTimer}>Stop</button>
<button onClick={resetTimer}>Reset</button>
</div>
</div>
);
}
export default Stopwatch;I executed the above example code and added the screenshot below.

What’s happening here:
- I used timerRef to store the interval ID.
- Because useRef persists across renders, the interval keeps running even when React re-renders the component.
- When I stop or reset the timer, I can easily clear the interval using clearInterval(timerRef.current).
This method is great for timers, animations, or tracking previous values without re-rendering your component.
Method 3 – Use useRef to Track Previous Values
Sometimes, you might want to compare the previous value of a prop or state variable with its current value. I often use this when debugging or optimizing performance.
Here’s how I do it:
Example: Tracking Previous State with useRef
import React, { useState, useEffect, useRef } from 'react';
function PreviousValueExample() {
const [count, setCount] = useState(0);
const prevCountRef = useRef();
useEffect(() => {
prevCountRef.current = count;
}, [count]);
const prevCount = prevCountRef.current;
return (
<div style={{ textAlign: 'center', marginTop: '50px' }}>
<h2>Count: {count}</h2>
<h3>Previous Count: {prevCount}</h3>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
export default PreviousValueExample;I executed the above example code and added the screenshot below.

How it works:
- I created a prevCountRef using useRef().
- Inside useEffect, I updated it after each render.
- This gives me access to the previous value of count without triggering a re-render.
This trick is super handy when you need to compare state changes, for example, tracking user actions or detecting changes in form inputs.
Common Mistakes When Using useRef
Here are a few things I’ve learned from experience:
- Don’t expect re-renders when updating ref.current.
Changing a ref’s value won’t cause the component to re-render; that’s by design. - Always initialize your ref properly.
If you plan to attach it to a DOM element, start with useRef(null). - Avoid overusing refs.
If you can manage something with state, use state. Refs are best for DOM access or storing mutable values.
When Should You Use useRef?
Here’s a quick summary of when I use useRef in real-world React apps:
| Use Case | Description |
|---|---|
| Access DOM elements | Focus input fields, scroll to elements, play/pause videos |
| Store mutable values | Track timers, intervals, or previous values |
| Avoid re-renders | Keep data between renders without triggering updates |
When I first started using React Hooks, I underestimated how powerful useRef could be. But over the years, it’s become one of my favorite tools for managing DOM interactions and keeping components lightweight.
Whether you’re building a data entry form for a U.S. business dashboard or a simple stopwatch app, mastering useRef will make your React code cleaner and more efficient.
You may read:
- React Component File Structure Best Practices
- How To Create a Navbar Component in React
- Difference between React Component and React Element
- Create a React Loading Spinner Component

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.