React useRef Hook: Manage DOM and Persistent Values Without Re-Renders
Last updated 2 months, 2 weeks ago | 81 views 75 5

Introduction: Why useRef
Matters in React
React’s rendering system is powerful, but sometimes, you need to store values that don’t trigger re-renders—like tracking a timer ID or referencing a DOM element. That’s where the useRef
Hook shines.
The useRef
Hook is often overlooked but extremely handy for scenarios where:
-
You need to directly interact with a DOM element.
-
You want to persist values between renders without causing a re-render.
-
You need to avoid using
useState
for non-UI-related values.
Think of useRef
as a box that holds a mutable value. You can change the value inside without causing your component to re-render.
Understanding useRef
(Step-by-Step)
1. Basic Syntax
const myRef = useRef(initialValue);
-
The
.current
property holds the mutable value. -
Unlike state, updating
.current
doesn’t trigger a re-render.
2. Accessing DOM Elements
You can use useRef
to reference a DOM node, similar to document.getElementById
.
import React, { useRef, useEffect } from 'react';
function FocusInput() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus(); // Focus the input on mount
}, []);
return <input ref={inputRef} placeholder="Type here..." />;
}
3. Storing Mutable Values
useRef
can store any value that persists across renders but doesn’t affect the UI.
function TimerTracker() {
const count = useRef(0);
const handleClick = () => {
count.current++;
console.log(`Clicked ${count.current} times`);
};
return <button onClick={handleClick}>Click Me</button>;
}
-
Note: This will not re-render the component when
count.current
changes.
4. Avoiding Unnecessary Re-Renders
If you store frequent updates in useState
, it causes re-renders. useRef
avoids that.
Comparison Table: useRef
vs useState
Feature | useRef |
useState |
---|---|---|
Triggers re-render | ❌ No | ✅ Yes |
Persists across renders | ✅ Yes | ✅ Yes |
Stores DOM refs | ✅ Yes | ❌ No |
Best use case | Timer ID, DOM access, caches | UI state, form values, etc. |
Complete Working Example: Form Focus & Timer Tracker
import React, { useRef, useEffect } from 'react';
function App() {
const inputRef = useRef(null);
const timerRef = useRef(null);
useEffect(() => {
inputRef.current.focus(); // Autofocus input on mount
timerRef.current = setInterval(() => {
console.log('Timer running...');
}, 1000);
return () => {
clearInterval(timerRef.current); // Cleanup on unmount
};
}, []);
const handleClick = () => {
alert(`Current input value: ${inputRef.current.value}`);
};
return (
<div style={{ padding: '20px' }}>
<input ref={inputRef} placeholder="Enter something..." />
<button onClick={handleClick} style={{ marginLeft: '10px' }}>
Show Input
</button>
</div>
);
}
export default App;
Tips & Common Pitfalls
✅ Best Practices
-
Use
useRef
for DOM manipulation or storing non-UI values. -
Name your refs clearly (
inputRef
,timerRef
) for readability. -
Clean up timers or subscriptions inside
useEffect
.
⚠️ Common Mistakes
-
Expecting re-renders: Changing
.current
won’t re-render the component. -
Accessing
.current
before mount: Always check if it'snull
when dealing with DOM refs. -
Overusing refs: Don’t use them for everything—state is still the right tool for UI-driven logic.
When to Use useRef
vs Other Hooks
Scenario | Recommended Hook |
---|---|
Accessing DOM elements | useRef |
Storing interval/timer IDs | useRef |
Persisting non-UI data | useRef |
UI-driven data (triggers re-render) | useState |
Sharing logic between components | useContext |
Conclusion: Master useRef
for Clean, Efficient React Code
The useRef
Hook is your best friend for dealing with:
-
Direct DOM interactions
-
Persistent mutable values
-
Avoiding performance hits from re-renders
Keep in mind: If your value doesn't affect the UI directly and doesn't need to trigger a render—useRef
is likely what you need.
✅ Actionable Takeaways
-
Use
useRef
to focus inputs or access other DOM nodes. -
Store mutable values like counters, timers, or cache references.
-
Avoid overusing state for non-visual logic—
useRef
is more performant. -
Combine
useRef
withuseEffect
for timed or delayed logic.