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! 🚀
Top comments (0)