smithery.ai

frontend-react-performance-optimization

Standardized guidelines and patterns for Frontend React Performance Optimization.

First seen Apr 5, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 6,501 B
  • docs SUMMARY.md 128 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Frontend React Performance Optimization

When to use this skill

  • Application is slow or laggy
  • Large lists causing performance issues
  • Unnecessary re-renders
  • Bundle size is too large
  • Improving Core Web Vitals

Workflow

  • Profile with React DevTools Profiler
  • Identify performance bottlenecks
  • Apply appropriate optimization technique
  • Measure improvement
  • Avoid premature optimization

Instructions

React.memo

Prevent unnecessary re-renders of components:

// Without memo - re-renders on every parent update
export const ExpensiveComponent = ({ data }: { data: string }) => {
  console.log('Rendering ExpensiveComponent');
  return <div>{data}</div>;
};

// With memo - only re-renders when data changes
export const ExpensiveComponent = React.memo(({ data }: { data: string }) => {
  console.log('Rendering ExpensiveComponent');
  return <div>{data}</div>;
});

// Custom comparison function
export const UserCard = React.memo(
  ({ user }: { user: User }) => <div>{user.name}</div>,
  (prevProps, nextProps) => {
    // Only re-render if user.id changed
    return prevProps.user.id === nextProps.user.id;
  }
);

useMemo

Memoize expensive calculations:

function ProductList({ products, searchTerm }: Props) {
  // ❌ Bad - filters on every render
  const filtered = products.filter(p => 
    p.name.includes(searchTerm)
  );

  // ✅ Good - only recalculates when dependencies change
  const filteredProducts = useMemo(() => {
    console.log('Filtering products');
    return products.filter(p => p.name.includes(searchTerm));
  }, [products, searchTerm]);

  return <div>{filteredProducts.map(...)}</div>;
}

useCallback

Memoize function references:

function Parent() {
  const [count, setCount] = useState(0);
  const [other, setOther] = useState(0);

  // ❌ Bad - new function on every render
  const handleClick = () => {
    setCount(count + 1);
  };

  // ✅ Good - same function reference
  const handleClick = useCallback(() => {
    setCount(c => c + 1);
  }, []); // Empty deps because we use functional update

  return <ExpensiveChild onClick={handleClick} />;
}

const ExpensiveChild = React.memo(({ onClick }: { onClick: () => void }) => {
  console.log('Child rendered');
  return <button onClick={onClick}>Click</button>;
});

Code Splitting

Route-based splitting:

import { lazy, Suspense } from 'react';

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

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/settings" element={<Settings />} />
      </Routes>
    </Suspense>
  );
}

Component-based splitting:

const HeavyChart = lazy(() => import('./components/HeavyChart'));

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

  return (
    <div>
      <button onClick={() => setShowChart(true)}>Show Chart</button>
      {showChart && (
        <Suspense fallback={<Skeleton />}>
          <HeavyChart data={data} />
        </Suspense>
      )}
    </div>
  );
}

Virtualization

For long lists, render only visible items:

import { FixedSizeList } from 'react-window';

function VirtualizedList({ items }: { items: string[] }) {
  const Row = ({ index, style }: { index: number; style: React.CSSProperties }) => (
    <div style={style}>
      {items[index]}
    </div>
  );

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

Debouncing & Throttling

// Debounce: Wait for pause in events
function SearchInput() {
  const [search, setSearch] = useState('');

  const debouncedSearch = useMemo(
    () => debounce((value: string) => {
      // API call
      fetchResults(value);
    }, 500),
    []
  );

  useEffect(() => {
    debouncedSearch(search);
  }, [search, debouncedSearch]);

  return <input value={search} onChange={e => setSearch(e.target.value)} />;
}

// Throttle: Limit frequency
function ScrollHandler() {
  const handleScroll = useCallback(
    throttle(() => {
      console.log('Scroll position:', window.scrollY);
    }, 200),
    []
  );

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [handleScroll]);

  return <div>Scroll me</div>;
}

Lazy State Initialization

// ❌ Bad - runs expensive function on every render
const [data, setData] = useState(expensiveComputation());

// ✅ Good - only runs once
const [data, setData] = useState(() => expensiveComputation());

// Example
const [user, setUser] = useState(() => {
  const stored = localStorage.getItem('user');
  return stored ? JSON.parse(stored) : null;
});

Key Optimization

// ❌ Bad - using index as key
{items.map((item, index) => (
  <Item key={index} data={item} />
))}

// ✅ Good - using stable unique identifier
{items.map(item => (
  <Item key={item.id} data={item} />
))}

useTransition (React 18+)

Mark non-urgent updates:

function SearchResults() {
  const [isPending, startTransition] = useTransition();
  const [search, setSearch] = useState('');
  const [results, setResults] = useState([]);

  const handleSearch = (value: string) => {
    setSearch(value); // Urgent: update input immediately

    startTransition(() => {
      // Non-urgent: filter can be delayed
      setResults(filterResults(value));
    });
  };

  return (
    <>
      <input value={search} onChange={e => handleSearch(e.target.value)} />
      {isPending ? <Spinner /> : <ResultsList results={results} />}
    </>
  );
}

Profiling Checklist

  • Use React DevTools Profiler
  • Check "Highlight updates"
  • Measure before optimizing
  • Profile in production mode
  • Use Chrome Lighthouse

Resources

  • Don't optimize prematurely
  • Measure first, optimize second
  • memo for expensive components
  • useMemo for expensive calculations
  • useCallback for stable references
  • Code split routes and heavy components