react-performance-optimizer

安装量: 48
排名: #15528

安装

npx skills add https://github.com/erichowens/some_claude_skills --skill react-performance-optimizer

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:

// ❌ 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:

// ✅ 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:

Computation takes >5ms (use Profiler to measure) Result used in dependency array Prevents child re-renders Anti-Pattern 2: Not Memoizing Callbacks

Problem: New function instance on every render breaks React.memo.

Wrong approach:

// ❌ 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:

// ✅ 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:

// ❌ Renders all 10,000 items function UserList({ users }) { return (

{users.map(user => ( ))}
); }

Correct approach:

// ✅ Only renders visible items import { FixedSizeList } from 'react-window';

function UserList({ users }) { return ( {({ index, style }) => (

)} ); }

Impact: 10,000 items: 5 seconds → 50ms render time.

Anti-Pattern 4: No Code Splitting

Problem: 2MB bundle downloaded upfront, slow initial load.

Wrong approach:

// ❌ Everything in main bundle import AdminPanel from './AdminPanel'; // 500KB import Dashboard from './Dashboard'; import Settings from './Settings';

function App() { return ( } /> } /> } /> ); }

Correct approach:

// ✅ Lazy load routes import { lazy, Suspense } from 'react';

const AdminPanel = lazy(() => import('./AdminPanel')); const Dashboard = lazy(() => import('./Dashboard')); const Settings = lazy(() => import('./Settings'));

function App() { return ( }> } /> } /> } /> ); }

Impact: Initial bundle: 2MB → 300KB.

Anti-Pattern 5: Expensive Operations in Render

Problem: Heavy computation on every render.

Wrong approach:

// ❌ Sorts on every render (even when data unchanged) function ProductList({ products }) { const sorted = products.sort((a, b) => b.price - a.price);

return

{sorted.map(p => )}
; }

Correct approach:

// ✅ Memoize expensive operation function ProductList({ products }) { const sorted = useMemo( () => [...products].sort((a, b) => b.price - a.price), [products] );

return

{sorted.map(p => )}
; }

Implementation Patterns Pattern 1: React.memo for Pure Components // Prevent re-render when props unchanged const ExpensiveComponent = React.memo(({ data }) => { // Complex rendering logic return

{/ ... /}
; });

// With custom comparison const UserCard = React.memo( ({ user }) =>

{user.name}
, (prevProps, nextProps) => { // Return true if props equal (skip re-render) return prevProps.user.id === nextProps.user.id; } );

Pattern 2: useMemo for Expensive Calculations function DataTable({ rows, columns }) { const sortedAndFiltered = useMemo(() => { console.log('Recomputing...'); // Only logs when rows/columns change

return rows
  .filter(row => row.visible)
  .sort((a, b) => a.timestamp - b.timestamp);

}, [rows, columns]);

return

; }

Pattern 3: useCallback for Stable References function SearchBox({ onSearch }) { const [query, setQuery] = useState('');

// Stable reference, doesn't break child memoization const handleSubmit = useCallback(() => { onSearch(query); }, [query, onSearch]);

return (
setQuery(e.target.value)} /> ); }

Pattern 4: Virtualization (react-window) import { VariableSizeList } from 'react-window';

function MessageList({ messages }) { const getItemSize = (index) => { // Dynamic heights based on content return messages[index].text.length > 100 ? 80 : 50; };

return ( {({ index, style }) => (

)} ); }

Pattern 5: Code Splitting with React.lazy // Route-based splitting const routes = [ { path: '/home', component: lazy(() => import('./Home')) }, { path: '/about', component: lazy(() => import('./About')) }, { path: '/contact', component: lazy(() => import('./Contact')) } ];

// Component-based splitting const HeavyChart = lazy(() => import('./HeavyChart'));

function Dashboard() { const [showChart, setShowChart] = useState(false);

return (

  {showChart && (
    <Suspense fallback={<Spinner />}>
      <HeavyChart />
    </Suspense>
  )}
</div>

); }

Production Checklist □ Profiler analysis completed (identified slow components) □ Large lists use virtualization (>100 items) □ Routes code-split with React.lazy □ Heavy components lazy-loaded □ Callbacks memoized with useCallback □ Expensive computations use useMemo □ Pure components wrapped in React.memo □ Bundle analyzed (no duplicate dependencies) □ Tree-shaking enabled (ESM imports) □ Images optimized and lazy-loaded □ Lighthouse score >90 □ Time to Interactive <3 seconds

When to Use vs Avoid Scenario Optimize? Rendering 1000+ list items ✅ Yes - virtualize Sorting/filtering large arrays ✅ Yes - useMemo Passing callbacks to memoized children ✅ Yes - useCallback String concatenation ❌ No - fast enough Simple arithmetic ❌ No - don't memoize 10-item list ❌ No - premature optimization References /references/profiling-guide.md - How to use React DevTools Profiler /references/bundle-optimization.md - Reduce bundle size strategies /references/memory-leaks.md - Detect and fix memory leaks Scripts scripts/performance_audit.ts - Automated performance checks scripts/bundle_analyzer.sh - Analyze and visualize bundle

This skill guides: React performance optimization | Memoization | Virtualization | Code splitting | Bundle optimization | Profiling

返回排行榜