React
Performance Optimization
Speed up React apps with memo, useMemo, useCallback, and component optimization techniques that make DataFlow dashboard blazing fast.
React performance matters. A slow dashboard frustrates users. DataFlow needs to handle thousands of transactions, real-time updates, and complex charts without lag. Performance optimization isn't premature optimization. It's about understanding how React works and preventing wasteful re-renders.Why React Apps Get Slow
React re-renders components when state or props change. But sometimes components re-render unnecessarily. Every re-render means JavaScript work, DOM updates, and potential lag. Common performance killers: - Parent components re-rendering all children - Expensive calculations running on every render - New objects created in JSX causing prop changes - Large lists without proper keys - Context updates triggering widespread re-renders The DataFlow dashboard has 50+ components. If the header re-renders, it shouldn't force the entire data table to re-render too.React.memo - Preventing Unnecessary Re-renders
React.memo wraps components and prevents re-renders when props haven't changed. Think of it like a smart bouncer that only lets through actual changes.
// DataFlow stats card without memo - re-renders always
function StatsCard({ title, value, icon }) {
console.log('StatsCard rendered:', title);
return (
<div style={{ padding: '20px', background: '#fff', borderRadius: '8px' }}>
<h3>{title}</h3>
<p style={{ fontSize: '24px', fontWeight: 'bold' }}>{value}</p>
</div>
);
}React.memo:
// Optimized with React.memo
const StatsCard = React.memo(function StatsCard({ title, value, icon }) {
console.log('StatsCard rendered:', title);
return (
<div style={{ padding: '20px', background: '#fff', borderRadius: '8px' }}>
<h3>{title}</h3>
<p style={{ fontSize: '24px', fontWeight: 'bold' }}>{value}</p>
</div>
);
});What just happened?
React.memo compared the props and skipped re-rendering because title and value didn't change. Click the button multiple times - the console stays quiet. Try this: Change a prop value and watch the component re-render only then.
useMemo - Caching Expensive Calculations
useMemo caches the result of expensive calculations. Only recalculates when dependencies change. Perfect for DataFlow's transaction processing.
// DataFlow transaction summary - expensive calculation
function TransactionSummary({ transactions }) {
// Expensive calculation - runs every render
const summary = transactions.reduce((acc, transaction) => {
acc.total += transaction.amount;
acc.count += 1;
if (transaction.type === 'sale') acc.sales += transaction.amount;
return acc;
}, { total: 0, count: 0, sales: 0 });
return (
<div>
<h3>Transaction Summary</h3>
<p>Total: ${summary.total.toLocaleString()}</p>
<p>Count: {summary.count}</p>
</div>
);
}useMemo:
// Optimized with useMemo
function TransactionSummary({ transactions }) {
// Only recalculate when transactions array changes
const summary = React.useMemo(() => {
console.log('Calculating summary...');
return transactions.reduce((acc, transaction) => {
acc.total += transaction.amount;
acc.count += 1;
if (transaction.type === 'sale') acc.sales += transaction.amount;
return acc;
}, { total: 0, count: 0, sales: 0 });
}, [transactions]);
return (
<div>
<h3>Transaction Summary</h3>
<p>Total: ${summary.total.toLocaleString()}</p>
</div>
);
}What just happened?
useMemo cached the calculation result. React only recalculates when the transactions dependency changes. Multiple re-renders use the cached value. Try this: Notice how the console message only appears once, even when clicking the button multiple times.
useCallback - Preventing Function Recreation
useCallback caches function definitions. Without it, every render creates new function objects, breaking memo comparisons and causing child re-renders.
// DataFlow filter component - function created every render
function FilteredTransactions({ transactions }) {
const [filter, setFilter] = React.useState('all');
// New function every render - breaks React.memo
const handleFilterChange = (newFilter) => {
setFilter(newFilter);
};
const filteredData = transactions.filter(tx =>
filter === 'all' ? true : tx.type === filter
);
return (
<div>
<FilterButtons onFilterChange={handleFilterChange} />
<TransactionList transactions={filteredData} />
</div>
);
}useCallback:
// Optimized with useCallback
function FilteredTransactions({ transactions }) {
const [filter, setFilter] = React.useState('all');
// Same function reference across renders
const handleFilterChange = React.useCallback((newFilter) => {
setFilter(newFilter);
}, []); // No dependencies - function never changes
const filteredData = React.useMemo(() =>
transactions.filter(tx =>
filter === 'all' ? true : tx.type === filter
), [transactions, filter]
);
return (
<div>
<FilterButtons onFilterChange={handleFilterChange} />
<TransactionList transactions={filteredData} />
</div>
);
}What just happened?
useCallback returned the same function reference each time, allowing React.memo to work properly. The memoized child component didn't re-render unnecessarily. Try this: Click the filter buttons to see they still work while avoiding pointless re-renders.
Component Optimization Strategies
Real apps need multiple optimization techniques working together. Here's how DataFlow's transaction table stays fast with 10,000+ rows:Virtual Scrolling
Only render visible rows. Libraries like react-window handle thousands of items smoothly.
Debounced Search
Wait 300ms after typing stops before filtering. Prevents excessive API calls and renders.
Lazy Components
Load heavy chart components only when needed. React.lazy + Suspense handle code splitting.
Smart Keys
Use stable, unique keys for list items. Helps React efficiently update and reorder elements.
Common Performance Pitfalls
Avoid these mistakes that kill React performance:Creating Objects in JSX
style={{padding: '20px'}} creates new objects every render. Move to CSS or useMemo for expensive styles.
Index as Key
key={index} breaks React's reconciliation when items reorder. Use stable IDs instead.
Overusing Context
Context updates re-render all consumers. Split contexts by update frequency and use selectors.
Quiz
1. The DataFlow stats component re-renders every time the parent updates, even though its revenue prop stays the same. What optimization should you use?
2. DataFlow processes 10,000 transactions on every render to calculate totals, even when the data hasn't changed. Which hook optimizes this?
3. A DataFlow filter component wrapped in React.memo still re-renders when its parent updates, even though the onFilter prop function does the same thing. Why?
Up Next: Code Splitting
Break large bundles into smaller chunks that load on demand - keep DataFlow fast even with massive feature sets.