Performance Optimization
React re-renders components when props or state change. Unnecessary re-renders waste resources. Optimize only when you have a measurable problem.
React.memo
Wrap components to skip re-renders when props haven’t changed.
const UserCard = React.memo(({ name, email }) => {
console.log("rendered");
return (
<div>
<h3>{name}</h3>
<p>{email}</p>
</div>
);
});
If the parent re-renders but name and email are the same, UserCard skips rendering.
useMemo
Cache expensive computations between re-renders.
const sorted = useMemo(() => {
return items.sort((a, b) => a.name.localeCompare(b.name));
}, [items]);
Only recalculates when items changes. Don’t memoize trivial calculations — the overhead may cost more than the savings.
useCallback
Stabilize function references passed as props.
const handleClick = useCallback((id) => {
setSelected(id);
}, []);
// Without useCallback, a new function is created every render,
// causing memo'd children to re-render.
Lazy Loading with Suspense
Load components only when needed.
import { lazy, Suspense } from "react";
const Dashboard = lazy(() => import("./Dashboard"));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Dashboard />
</Suspense>
);
}
Reduces initial bundle size. Great for routes and heavy components.
Profiling with DevTools
Use React DevTools Profiler to find actual bottlenecks.
- Record a session
- Identify which components re-render and how long they take
- Optimize only the slow components
When to Optimize
- Don’t premature optimize — most apps are fast enough
- Optimize when users report slowness or Profiler shows issues
- Large lists, frequent updates, and heavy computations benefit most
- Small apps with few components rarely need memoization
Best Practices
- Profile before optimizing — measure, don’t guess
- Use
React.memofor components that receive stable props - Use
useMemofor expensive calculations, not every value - Use
useCallbackwhen passing functions to memoized children - Lazy-load routes and heavy components with
React.lazy - Keep component trees shallow — avoid deep nesting
Common Mistakes
- Memoizing everything blindly adds complexity with no benefit
- Creating new objects/arrays in render defeats
useMemo - Passing inline objects or functions to memoized children
- Forgetting dependency arrays in
useMemoanduseCallback - Optimizing before measuring — always profile first