React Performance Optimization Guide
React Performance Optimization Guide
React is incredibly powerful, but as your app grows, performance bottlenecks can creep in. In this guide, we'll cover the most effective strategies for keeping your React apps fast and responsive.
Understanding Re-renders
Every time a component's state or props change, React re-renders it. While React's virtual DOM makes this efficient, unnecessary re-renders can still cause performance issues, especially in large applications.
// ❌ Bad: Creates a new object on every render
function App() {
return <Child style={{ color: 'red' }} />;
}
// ✅ Good: Stable reference
const style = { color: 'red' };
function App() {
return <Child style={style} />;
}
React.memo — Your First Line of Defense
React.memo is a higher-order component that prevents re-renders if props haven't changed:
const ExpensiveComponent = React.memo(({ data }) => {
// This only re-renders when `data` changes
return <div>{processData(data)}</div>;
});
When to use React.memo:
- Components that render often with the same props
- Components with expensive rendering logic
- Components deep in the tree that receive stable props
useMemo and useCallback
These hooks help you memoize values and functions:
function SearchResults({ query, filters }) {
// Memoize expensive computation
const results = useMemo(
() => filterAndSort(data, query, filters),
[data, query, filters]
);
// Memoize callback to prevent child re-renders
const handleClick = useCallback(
(id) => selectItem(id),
[selectItem]
);
return <ResultList items={results} onClick={handleClick} />;
}
State Management Best Practices
1. Keep State Local
Don't lift state higher than necessary. If only one component needs a piece of state, keep it there.
2. Split Context
Instead of one massive context, split into focused contexts:
// ❌ One giant context
const AppContext = createContext({ user, theme, cart, notifications });
// ✅ Split contexts
const UserContext = createContext(user);
const ThemeContext = createContext(theme);
const CartContext = createContext(cart);
3. Use State Selectors
With libraries like Zustand, use selectors to subscribe to specific slices:
// Only re-renders when `count` changes
const count = useStore((state) => state.count);
Profiling Your App
Use the React DevTools Profiler to identify slow renders:
- Open React DevTools → Profiler tab
- Click Record and interact with your app
- Look for components with long render times
- Check "Why did this render?" to understand the cause
Key Takeaways
- Measure first — don't optimize blindly
- React.memo for pure components with stable props
- useMemo/useCallback for expensive computations and stable references
- Split context to avoid cascading re-renders
- Keep state local whenever possible
- Profile regularly to catch regressions early
Performance optimization is not about making everything fast — it's about making the right things fast at the right time.
Happy optimizing! 🚀