useMemo and useCallback
Master useMemo and useCallback hooks for optimizing expensive calculations and preventing unnecessary re-renders. This is a foundational concept in component-based UI development that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world React experience. Take your time with each section and practice the examples
useMemo Hook
useMemo is a React hook that memoizes the result of a computation. It only recalculates the value when one of its dependencies changes.. This is an essential concept that every React developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
useMemo Examples
import React, { useState, useMemo } from 'react';
function ExpensiveCalculation({ numbers }) {
// Expensive calculation that only runs when numbers change
const expensiveValue = useMemo(() => {
return numbers.reduce((sum, num) => sum + num, 0) * 1000;
}, [numbers]);
return (
<div>
<h2>Expensive Calculation Result: {expensiveValue}</h2>
<p>Numbers: {numbers.join(', ')}</p>
</div>
);
}
// Filtering and sorting with useMemo
function UserList({ users, searchTerm, sortBy }) {
const filteredAndSortedUsers = useMemo(() => {
let filtered = users.filter(user =>
user.name.toLowerCase().includes(searchTerm.toLowerCase())
);
if (sortBy === 'name') {
filtered.sort((a, b) => a.name.localeCompare(b.name));
} else if (sortBy === 'age') {
filtered.sort((a, b) => a.age - b.age);
}
return filtered;
}, [users, searchTerm, sortBy]);
return (
<div>
{filteredAndSortedUsers.map(user => (
<div key={user.id}>
<h3>{user.name}</h3>
<p>Age: {user.age}</p>
</div>
))}
</div>
);
}useCallback Hook
// useCallback for memoizing functions
import React, { useState, useCallback } from 'react';
function ParentComponent() {
const [count, setCount] = useState(0);
const [users, setUsers] = useState([]);
// Memoized callback that only changes when count changes
const handleIncrement = useCallback(() => {
setCount(c => c + 1);
}, []);
// Memoized callback for user operations
const handleAddUser = useCallback((newUser) => {
setUsers(prev => [...prev, newUser]);
}, []);
const handleDeleteUser = useCallback((userId) => {
setUsers(prev => prev.filter(user => user.id !== userId));
}, []);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={handleIncrement}>Increment</button>
<UserList
users={users}
onAddUser={handleAddUser}
onDeleteUser={handleDeleteUser}
/>
</div>
);
}
// Child component that benefits from memoized callbacks
const UserList = React.memo(function UserList({ users, onAddUser, onDeleteUser }) {
return (
<div>
{users.map(user => (
<UserItem
key={user.id}
user={user}
onDelete={onDeleteUser}
/>
))}
</div>
);
});