Claude
Skills
Sign in
Back

react-performance

Included with Lifetime
$97 forever

Use when React performance optimization including memoization, lazy loading, and virtualization. Use when optimizing React applications.

Web Dev

What this skill does


# React Performance Optimization

Master react performance optimization for building high-performance, scalable
React applications with industry best practices.

## React.memo and Component Memoization

React.memo prevents unnecessary re-renders by memoizing component output:

```typescript
import { memo } from 'react';

interface Props {
  name: string;
  onClick: () => void;
}

// Basic memoization
const ExpensiveComponent = memo(
  function ExpensiveComponent({ name, onClick }: Props) {
  console.log('Rendering ExpensiveComponent');
  return <button onClick={onClick}>{name}</button>;
});

// Custom comparison function
const CustomMemo = memo(
  function Component({ user }: { user: User }) {
    return <div>{user.name}</div>;
  },
  (prevProps, nextProps) => {
    // Return true if passing nextProps would return the same result as prevProps
    return prevProps.user.id === nextProps.user.id;
  }
);

// When to use custom comparison
const ProductCard = memo(
  function ProductCard({ product }: { product: Product }) {
    return (
      <div>
        <h3>{product.name}</h3>
        <p>${product.price}</p>
      </div>
    );
  },
  (prev, next) => {
    // Only re-render if these specific fields change
    return (
      prev.product.id === next.product.id &&
      prev.product.name === next.product.name &&
      prev.product.price === next.product.price
    );
  }
);
```

## useMemo for Expensive Computations

```typescript
import { useMemo, useState } from 'react';

function DataTable({ items }: { items: Item[] }) {
  const [filter, setFilter] = useState('');
  const [sortBy, setSortBy] = useState<'name' | 'price'>('name');

  // Expensive filtering and sorting
  const processedItems = useMemo(() => {
    console.log('Computing filtered and sorted items');
    return items
      .filter(item => item.name.toLowerCase().includes(filter.toLowerCase()))
      .sort((a, b) => {
        if (sortBy === 'name') {
          return a.name.localeCompare(b.name);
        }
        return a.price - b.price;
      });
  }, [items, filter, sortBy]);

  // Expensive aggregate calculation
  const statistics = useMemo(() => {
    console.log('Computing statistics');
    return {
      total: processedItems.reduce((sum, item) => sum + item.price, 0),
      average: processedItems.length
        ? processedItems.reduce((sum, item) => sum + item.price, 0) / processedItems.length
        : 0,
      count: processedItems.length
    };
  }, [processedItems]);

  return (
    <>
      <input value={filter} onChange={(e) => setFilter(e.target.value)} />
      <select value={sortBy} onChange={(e) => setSortBy(e.target.value as any)}>
        <option value="name">Name</option>
        <option value="price">Price</option>
      </select>
      <div>Total: ${statistics.total}</div>
      <div>Average: ${statistics.average.toFixed(2)}</div>
      <div>Count: {statistics.count}</div>
      {processedItems.map(item => (
        <div key={item.id}>{item.name} - ${item.price}</div>
      ))}
    </>
  );
}
```

## useCallback for Stable Function References

```typescript
import { useCallback, useState, memo } from 'react';

// Child component that only re-renders when necessary
const ListItem = memo(function ListItem({
  item,
  onDelete
}: {
  item: Item;
  onDelete: (id: string) => void;
}) {
  console.log('Rendering ListItem', item.id);
  return (
    <div>
      {item.name}
      <button onClick={() => onDelete(item.id)}>Delete</button>
    </div>
  );
});

function OptimizedList({ items }: { items: Item[] }) {
  const [deletedIds, setDeletedIds] = useState<Set<string>>(new Set());

  // Without useCallback, this creates a new function on every render
  // causing ListItem to re-render even with memo
  const handleDelete = useCallback((id: string) => {
    setDeletedIds(prev => new Set([...prev, id]));
    // API call to delete
    api.deleteItem(id);
  }, []); // Empty deps means function never changes

  const handleDeleteWithDeps = useCallback((id: string) => {
    console.log('Already deleted:', deletedIds.size);
    setDeletedIds(prev => new Set([...prev, id]));
  }, [deletedIds]); // Re-create when deletedIds changes

  const visibleItems = items.filter(item => !deletedIds.has(item.id));

  return (
    <>
      {visibleItems.map(item => (
        <ListItem key={item.id} item={item} onDelete={handleDelete} />
      ))}
    </>
  );
}
```

## Code Splitting with React.lazy and Suspense

```typescript
import { lazy, Suspense } from 'react';
import { Routes, Route } from 'react-router-dom';

// Lazy load route components
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Profile = lazy(() => import('./pages/Profile'));
const Settings = lazy(() => import('./pages/Settings'));
const Analytics = lazy(() => import('./pages/Analytics'));

// Fallback component
function LoadingSpinner() {
  return <div className="spinner">Loading...</div>;
}

function App() {
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <Routes>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/profile" element={<Profile />} />
        <Route path="/settings" element={<Settings />} />
        <Route path="/analytics" element={<Analytics />} />
      </Routes>
    </Suspense>
  );
}

// Preload on hover for better UX
function Navigation() {
  const preloadDashboard = () => import('./pages/Dashboard');
  const preloadProfile = () => import('./pages/Profile');

  return (
    <nav>
      <a href="/dashboard" onMouseEnter={preloadDashboard}>Dashboard</a>
      <a href="/profile" onMouseEnter={preloadProfile}>Profile</a>
    </nav>
  );
}

// Nested Suspense boundaries
function DashboardLayout() {
  const Header = lazy(() => import('./components/Header'));
  const Sidebar = lazy(() => import('./components/Sidebar'));
  const Content = lazy(() => import('./components/Content'));

  return (
    <div className="dashboard">
      <Suspense fallback={<div>Loading header...</div>}>
        <Header />
      </Suspense>
      <Suspense fallback={<div>Loading sidebar...</div>}>
        <Sidebar />
      </Suspense>
      <Suspense fallback={<div>Loading content...</div>}>
        <Content />
      </Suspense>
    </div>
  );
}
```

## Virtual Scrolling for Large Lists

```typescript
import { FixedSizeList, VariableSizeList } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';

// Fixed size items
function VirtualList({ items }: { items: string[] }) {
  const Row = ({ index, style }: {
    index: number;
    style: React.CSSProperties
  }) => (
    <div style={style} className="list-item">
      {items[index]}
    </div>
  );

  return (
    <FixedSizeList
      height={600}
      itemCount={items.length}
      itemSize={35}
      width="100%"
    >
      {Row}
    </FixedSizeList>
  );
}

// Variable size items
function VariableList({ items }: { items: Post[] }) {
  const getItemSize = (index: number) => {
    // Calculate height based on content
    return items[index].content.length > 100 ? 120 : 80;
  };

  const Row = ({ index, style }: any) => (
    <div style={style} className="post">
      <h3>{items[index].title}</h3>
      <p>{items[index].content}</p>
    </div>
  );

  return (
    <VariableSizeList
      height={600}
      itemCount={items.length}
      itemSize={getItemSize}
      width="100%"
    >
      {Row}
    </VariableSizeList>
  );
}

// With AutoSizer for responsive layouts
function ResponsiveList({ items }: { items: Item[] }) {
  return (
    <div style={{ height: '100vh', width: '100%' }}>
      <AutoSizer>
        {({ height, width }) => (
          <FixedSizeList
            height={height}
            itemCount={items.length}
            itemSize={50}
            width={width}
          >
            {({ index, style }) => (
              <div style={style}>{items[index].name}</div>
            )}
          </FixedSizeList>
        )}
      </AutoSizer>
    </div>
  );
}
```

## React Profiler API for Performance 

Related in Web Dev