Understanding the distinction between side effects and memoization is what separates beginner React developers from senior engineers. `useEffect` handles asynchronous side effects, while `useMemo` and `useCallback` cache calculation results and function references across component renders.
1. `useEffect` & Cleanup Subscriptions
useEffect(() => {
// 1. Subscribe to WebSocket or Event Listener
const handleResize = () => setWindowWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
// 2. Cleanup function to prevent memory leaks
return () => window.removeEventListener('resize', handleResize);
}, []); // Empty dependency array = Runs once on mount
// 1. Subscribe to WebSocket or Event Listener
const handleResize = () => setWindowWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
// 2. Cleanup function to prevent memory leaks
return () => window.removeEventListener('resize', handleResize);
}, []); // Empty dependency array = Runs once on mount
2. `useMemo` vs `useCallback`: Comparison
| Hook | What it Caches | Best Use Case |
|---|---|---|
useMemo |
The result of a calculation (value/object/array). | Expensive filtering, sorting large 10,000+ item arrays. |
useCallback |
The function instance reference itself. | Passing callback handlers to memoized child components (React.memo). |
3. Live Performance Code Example
import React, { useState, useMemo, useCallback } from 'react';
export default function FilteredUserList({ users }) {
const [search, setSearch] = useState('');
// 1. useMemo caches expensive filtering calculation
const filteredUsers = useMemo(() => {
return users.filter(u => u.name.toLowerCase().includes(search.toLowerCase()));
}, [users, search]);
// 2. useCallback preserves function reference for child component
const handleDelete = useCallback((userId) => {
console.log("Deleting user:", userId);
}, []);
return (
<div className="p-4 border rounded">
<input type="text" value={search} onChange={e => setSearch(e.target.value)} placeholder="Filter users..." className="form-control mb-3" />
<p>Found: {filteredUsers.length} users</p>
</div>
);
}
export default function FilteredUserList({ users }) {
const [search, setSearch] = useState('');
// 1. useMemo caches expensive filtering calculation
const filteredUsers = useMemo(() => {
return users.filter(u => u.name.toLowerCase().includes(search.toLowerCase()));
}, [users, search]);
// 2. useCallback preserves function reference for child component
const handleDelete = useCallback((userId) => {
console.log("Deleting user:", userId);
}, []);
return (
<div className="p-4 border rounded">
<input type="text" value={search} onChange={e => setSearch(e.target.value)} placeholder="Filter users..." className="form-control mb-3" />
<p>Found: {filteredUsers.length} users</p>
</div>
);
}
Build Ultra-Fast Web Apps with Telugu IT Tutorials
Master React 19 performance profiling and component optimization techniques in our live virtual cohorts. Explore Courses →