React Mastery Series – Day 14: React Hooks Deep Dive – Understanding useRef and useMemo
Welcome back to the React Mastery Series! In the previous article, we explored useEffect Hook and learned how React handles side effects such as: API calls Timers Event listeners WebSocket connections Cleanup operatio
Welcome back to the React Mastery Series!
In the previous article, we explored useEffect Hook and learned how React handles side effects such as:
- API calls
- Timers
- Event listeners
- WebSocket connections
- Cleanup operations
Today, we will explore two more powerful React Hooks:
useRef and useMemo
These Hooks are frequently used in production applications to:
- Access DOM elements
- Store values without triggering re-renders
- Optimize expensive calculations
- Improve application performance
Understanding useRef Hook
useRef is a React Hook that allows us to store a value that persists across renders without causing the component to re-render.
Syntax:
const reference = useRef(initialValue);
The returned object looks like:
{
current: initialValue
}
The value is accessed using:
reference.current
useRef vs useState
A common question:
Why do we need useRef when we already have useState?
The difference:
| useState | useRef |
|---|---|
| Updates trigger re-render | Updates do not trigger re-render |
| Used for UI data | Used for storing values |
| React tracks changes | React does not track changes |
Example:
const [count, setCount] = useState(0);
Updating:
setCount(count + 1);
causes:
State Update
|
↓
Component Re-render
With useRef:
const count = useRef(0);
Updating:
count.current++;
does:
Value Updated
|
↓
No Re-render
Using useRef to Access DOM Elements
One of the most common use cases of useRef is accessing DOM elements directly.
Example:
import { useRef } from "react";
function SearchBox() {
const inputRef = useRef();
function focusInput() {
inputRef.current.focus();
}
return (
<div>
<input ref={inputRef} />
<button onClick={focusInput}>Focus Input</button>
</div>
);
}
Flow:
Button Click
|
↓
focusInput()
|
↓
inputRef.current
|
↓
Input DOM Element
|
↓
focus()
Real-World Example: Login Page
Imagine a banking login page.
When the page loads:
Open Login Page
|
↓
Username Field Automatically Focused
Implementation:
useEffect(()=>{
usernameRef.current.focus();
},[]);
This improves user experience.
Storing Previous Values Using useRef
useRef can store previous values.
Example:
function Profile({ name }) {
const previousName = useRef();
useEffect(() => {
previousName.current = name;
}, [name]);
return (
<div>
Current:
{name}
<br />
Previous:
{previousName.current}
</div>
);
}
The value survives between renders.
Tracking Render Count
Example:
function App() {
const renderCount = useRef(0);
renderCount.current++;
return (
<p>
Render Count:
{renderCount.current}
</p>
);
}
Unlike state, updating this value does not trigger another render.
Storing Timer References
Example:
function Timer() {
const timerRef = useRef();
function startTimer() {
timerRef.current = setInterval(() => {
console.log("Running");
}, 1000);
}
function stopTimer() {
clearInterval(timerRef.current);
}
}
Common use cases:
- Countdown timers
- Debounce logic
- Polling APIs
Real-World Example: WebSocket Connection
In enterprise applications:
Dashboard Open
|
↓
Create WebSocket
|
↓
Store Connection Reference
|
↓
Receive Messages
|
↓
Close Connection
Example:
const socketRef = useRef(null);
useEffect(() => {
socketRef.current = new WebSocket("wss://example.com");
return () => {
socketRef.current.close();
};
}, []);
Understanding useMemo Hook
Now let's explore:
useMemo
useMemo is used to optimize expensive calculations by memorizing a computed value.
Syntax:
const result = useMemo(
() => calculation,
[dependencies]
);
React remembers the result and recalculates only when dependencies change.
Why Do We Need useMemo?
Consider:
function ProductList() {
const products = calculateProducts();
return <Product products={products} />;
}
Every render:
Component Render
|
↓
calculateProducts()
|
↓
Heavy Calculation
Even when data has not changed.
This can impact performance.
Using useMemo
Example:
const filteredProducts = useMemo(() => {
return products.filter((product) => product.price > 1000);
}, [products]);
Now:
products unchanged
|
↓
Use Previous Result
products changed
|
↓
Recalculate
useMemo Example: Expensive Calculation
Without useMemo:
function App() {
const result = heavyCalculation(value);
return <h1>{result}</h1>;
}
The calculation runs on every render.
With useMemo:
function App() {
const result = useMemo(() => {
return heavyCalculation(value);
}, [value]);
return <h1>{result}</h1>;
}
The calculation runs only when value changes.
useMemo with Search Filtering
Real-world example:
const filteredUsers = useMemo(() => {
return users.filter((user) => user.name.includes(searchText));
}, [users, searchText]);
Used in:
- User management systems
- Product search
- Transaction filtering
useMemo vs useEffect
A common confusion.
useEffect
Used for:
- API calls
- Side effects
- External systems
Example:
useEffect(()=>{
fetchUsers();
},[]);
useMemo
Used for:
- Calculating values
- Performance optimization
Example:
const total = useMemo(()=>{
return calculateTotal(items);
},[items]);
useMemo vs useCallback
These Hooks are related but different.
| Hook | Purpose |
|---|---|
| useMemo | Memoize values |
| useCallback | Memoize functions |
Example:
useMemo:
const total = useMemo(()=>calculateTotal(),[]);
useCallback:
const handleClick = useCallback(()=>{
saveData();
},[]);
We will explore useCallback in detail in the next article.
Real-World Example: Banking Dashboard
Imagine a dashboard displaying:
- Account summary
- Transaction history
- Spending analysis
Data:
Transactions
|
↓
Calculate Monthly Spending
|
↓
Generate Chart Data
|
↓
Render Dashboard
Without optimization:
Every UI update
|
↓
Recalculate Everything
With useMemo:
Transactions Changed
|
↓
Recalculate Chart Data
Otherwise
Reuse Previous Calculation
Common Mistakes
1. Using useMemo Everywhere
Incorrect:
const name = useMemo(()=>user.name,[user]);
This creates unnecessary complexity.
Use useMemo only for:
- Expensive calculations
- Performance issues
2. Incorrect Dependencies
Example:
useMemo(()=>{
return calculate(items);
},[]);
Problem:
items is missing.
Correct:
useMemo(()=>{
return calculate(items);
},[items]);
3. Mutating useRef Values Expecting UI Updates
Example:
count.current++;
The UI will not update.
Use:
setCount()
when UI should change.
Best Practices
- Use useRef for persistent mutable values.
- Use useRef when you need DOM access.
- Use useMemo only for expensive computations.
- Do not optimize prematurely.
- Keep dependency arrays accurate.
- Measure performance before optimization.
Key Takeaways
Today, we learned:
✅ useRef stores values without causing re-renders.
✅ useRef can access DOM elements directly.
✅ useMemo caches expensive calculations.
✅ useMemo improves performance when used correctly.
✅ useState, useEffect, useRef, and useMemo solve different problems.
Coming Next 🚀
In Day 15, we will explore:
React Hooks Deep Dive – useCallback and React.memo
We will learn:
- Function memoization
- Preventing unnecessary child renders
- React.memo optimization
- Passing callbacks efficiently
- Performance optimization patterns
- Real-world component optimization
These concepts are extremely important when building large-scale React applications.
Happy Coding! 🚀
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.