1. Component Optimization Techniques
Memoization Strategies
// Component memoization
const MemoizedComponent = React.memo(MyComponent, (prevProps, nextProps) => {
return prevProps.value === nextProps.value;
});
// Value memoization
const expensiveValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
// Function memoization
const handleClick = useCallback(() => {
performAction(itemId);
}, [itemId]);
Key Optimization Principles
- Shallow prop comparisons: Ensure memoized components receive primitive props when possible
- Stable references: Maintain consistent object/array references across renders
- Selective updates: Split large components into smaller, isolated pieces
2. Rendering Optimization
Virtualized Lists
import { VariableSizeList } from 'react-window';
const rowHeights = items.map(item => item.expanded ? 100 : 50);
const List = () => (
<VariableSizeList
height={600}
itemCount={items.length}
itemSize={index => rowHeights[index]}
width="100%"
>
{({ index, style }) => (
<div style={style}>
<ListItem item={items[index]} />
</div>
)}
</VariableSizeList>
);
Lazy Loading Components
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
const MyComponent = () => (
<Suspense fallback={<Spinner />}>
<HeavyComponent />
</Suspense>
);
3. State Management Optimization
Context Optimization Patterns
// Split contexts
const UserContext = createContext();
const PreferencesContext = createContext();
// Selector pattern
const useUserSelector = (selector) => {
const user = useContext(UserContext);
return useMemo(() => selector(user), [user, selector]);
};
// Usage
const userName = useUserSelector(user => user.name);
State Colocation Examples
// Before: Lifted state
const Parent = () => {
const [state, setState] = useState();
return (
<>
<ChildA state={state} />
<ChildB setState={setState} />
</>
);
};
// After: Colocated state
const Parent = () => (
<>
<ChildA />
<ChildB />
</>
);
4. Bundle Optimization
Code Splitting Strategies
// Route-based splitting
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import(/* webpackChunkName: "about" */ './routes/About'));
// Library splitting
const HeavyLibrary = lazy(() => import('heavy-library'));
// Dynamic imports
const loadComponent = () => import('./DynamicComponent');
Tree Shaking Techniques
// Import only what you need
import { Button } from 'large-ui-library';
// Configure sideEffects in package.json
{
"sideEffects": [
"*.css",
"*.scss"
]
}
5. Advanced Performance Patterns
Concurrent Mode Features
// Transition updates
const [isPending, startTransition] = useTransition();
const [resource, setResource] = useState();
const fetchData = () => {
startTransition(() => {
setResource(fetchResource());
});
};
// Deferred values
const deferredValue = useDeferredValue(value);
Web Workers Integration
// Worker setup
const worker = new Worker('./worker.js');
// Component usage
const [result, setResult] = useState();
useEffect(() => {
worker.onmessage = (e) => setResult(e.data);
worker.postMessage(data);
}, [data]);
6. Debugging and Measurement
Performance Monitoring
// React DevTools Profiler integration
import { unstable_trace as trace } from 'scheduler/tracing';
const handleClick = () => {
trace('Button click', performance.now(), () => {
setState(prev => prev + 1);
});
};
// Custom timing hooks
const useRenderTime = () => {
const start = useRef(performance.now());
useEffect(() => {
const duration = performance.now() - start.current;
console.log(`Render took ${duration.toFixed(2)}ms`);
});
};
Optimization Checklist
- [ ] Memoize expensive components
- [ ] Implement virtualized lists for large datasets
- [ ] Use code splitting for routes/components
- [ ] Optimize context providers
- [ ] Avoid unnecessary state updates
- [ ] Use production builds for benchmarking
- [ ] Implement bundle analysis (Webpack Bundle Analyzer)
- [ ] Enable React’s Strict Mode for detection
- [ ] Use React.memo/useMemo/useCallback appropriately
- [ ] Profile before and after optimizations
Remember that optimization should be data-driven – always measure performance before and after applying changes to verify improvements. Start with the biggest bottlenecks first, and avoid premature optimization that adds unnecessary complexity.