---
name: react-performance-optimizer
description: Optimize React apps for 60fps performance. Implements memoization, virtualization, code splitting, bundle optimization. Use for slow renders, large lists, bundle bloat. Activate on "React performance",
"slow render", "useMemo", "bundle size", "virtualization". NOT for backend optimization, non-React frameworks, or premature optimization.
allowed-tools: Read,Write,Edit,Bash(npm:*)
metadata:
tags:
- react
- performance
- optimizer
- react-performance
- slow-render
pairs-with:
- skill: performance-profiling
reason: React profiling tools identify the re-render bottlenecks that optimization addresses
- skill: nextjs-app-router-expert
reason: RSC and streaming SSR in Next.js require React-specific performance strategies
- skill: data-viz-2025
reason: Data-heavy visualizations require React memoization and virtualization for smooth rendering
- skill: reactive-dashboard-performance
reason: Dashboard widgets with real-time data need the same React optimization patterns
---
# React Performance Optimizer
Expert in diagnosing and fixing React performance issues to achieve buttery-smooth 60fps experiences.
## When to Use
✅ **Use for**:
- Slow component re-renders
- Large lists (>100 items) causing lag
- Bundle size >500KB (gzipped)
- Time to Interactive >3 seconds
- Janky scrolling or animations
- Memory leaks from unmounted components
❌ **NOT for**:
- Apps with <10 components (premature optimization)
- Backend API slowness (fix the API)
- Network latency (use caching/CDN)
- Non-React frameworks (use framework-specific tools)
## Quick Decision Tree
```
Is your React app slow?
├── Profiler shows >16ms renders? → Use memoization
├── Lists with >100 items? → Use virtualization
├── Bundle size >500KB? → Code splitting
├── Lighthouse score <70? → Multiple optimizations
└── Feels fast enough? → Don't optimize yet
```
---
## Technology Selection
### Performance Tools (2024)
| Tool | Purpose | When to Use |
|------|---------|-------------|
| React DevTools Profiler | Find slow components | Always start here |
| Lighthouse | Overall performance score | Before/after comparison |
| webpack-bundle-analyzer | Identify large dependencies | Bundle >500KB |
| why-did-you-render | Unnecessary re-renders | Debug re-render storms |
| React Compiler (2024+) | Automatic memoization | React 19+ |
**Timeline**:
- 2018: React.memo, useMemo, useCallback introduced
- 2020: Concurrent Mode (now Concurrent Rendering)
- 2022: Automatic batching in React 18
- 2024: React Compiler (automatic optimization)
- 2025+: React Compiler expected to replace manual memoization
---
## Common Anti-Patterns
### Anti-Pattern 1: Premature Memoization
**Novice thinking**: "Wrap everything in useMemo for speed"
**Problem**: Adds complexity and overhead for negligible gains.
**Wrong approach**:
```typescript
// ❌ Over-optimization
function UserCard({ user }) {
const fullName = useMemo(() => `${user.first} ${user.last}`, [user]);
const age = useMemo(() => new Date().getFullYear() - user.birthYear, [user]);
return
{fullName}, {age}
;
}
```
**Why wrong**: String concatenation is faster than useMemo overhead.
**Correct approach**:
```typescript
// ✅ Simple is fast
function UserCard({ user }) {
const fullName = `${user.first} ${user.last}`;
const age = new Date().getFullYear() - user.birthYear;
return
{fullName}, {age}
;
}
```
**Rule of thumb**: Only memoize if:
1. Computation takes >5ms (use Profiler to measure)
2. Result used in dependency array
3. Prevents child re-renders
---
### Anti-Pattern 2: Not Memoizing Callbacks
**Problem**: New function instance on every render breaks React.memo.
**Wrong approach**:
```typescript
// ❌ Child re-renders on every parent render
function Parent() {
const [count, setCount] = useState(0);
return (
setCount(count + 1)} />
);
}
const Child = React.memo(({ onUpdate }) => {
return ;
});
```
**Why wrong**: Arrow function creates new reference → React.memo useless.
**Correct approach**:
```typescript
// ✅ Stable callback reference
function Parent() {
const [count, setCount] = useState(0);
const handleUpdate = useCallback(() => {
setCount(c => c + 1); // Updater function avoids dependency
}, []);
return ;
}
const Child = React.memo(({ onUpdate }) => {
return ;
});
```
---
### Anti-Pattern 3: Rendering Large Lists Without Virtualization
**Problem**: Rendering 1000+ DOM nodes causes lag.
**Symptom**: Scrolling feels janky, initial render slow.
**Wrong approach**:
```typescript
// ❌ Renders all 10,000 items
function UserList({ users }) {
return (