agentsclimarketplace

React performance

Skill Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack/plugins/devtools-pack/skills/react-performance

When to activate: React performance optimization, bundle size, code splitting, lazy loading, profiler, memoization, concurrent featuresFrom its SKILL.md

Install
npx -y skills add Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack --skill react-performance

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

5.5 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it

React Performance Patterns

Profiling First

// React DevTools Profiler — always profile before optimizing
// Enable in DevTools → Profiler → Record

// Code profiling with React Profiler API
import { Profiler, type ProfilerOnRenderCallback } from 'react'

const onRender: ProfilerOnRenderCallback = (id, phase, actualDuration) => {
  if (actualDuration > 16) {  // > 1 frame
    console.warn(`Slow render: ${id} (${phase}) took ${actualDuration.toFixed(1)}ms`)
  }
}

<Profiler id="Dashboard" onRender={onRender}>
  <Dashboard />
</Profiler>

Memoization

When to use memo / useMemo / useCallback

// memo: stable component with expensive render and stable-ish props
const ExpensiveChart = memo(function Chart({ data }: { data: DataPoint[] }) {
  // renders a big SVG chart
  return <svg>...</svg>
}, (prev, next) => prev.data === next.data)

// useMemo: CPU-expensive pure computation (not just "avoid re-render")
const sortedItems = useMemo(
  () => [...items].sort((a, b) => a.priority - b.priority),
  [items]  // only re-sort when items changes
)

// useCallback: stable function ref passed to memoized child or used as dep
const handleSelect = useCallback((id: string) => {
  setSelected(id)
  onSelect(id)
}, [onSelect])  // onSelect itself needs to be stable

Anti-patterns

// BAD: memoizing cheap computations (overhead > savings)
const name = useMemo(() => user.firstName + ' ' + user.lastName, [user])

// BAD: memo on component that receives new object literals every render
function Parent() {
  return <Child style={{ color: 'red' }} />  // new object each render
}

// GOOD: extract stable values
const style = { color: 'red' }  // module-level constant
function Parent() { return <Child style={style} /> }

State Colocation

// BAD: state too high — re-renders entire tree on every keystroke
function App() {
  const [search, setSearch] = useState('')  // re-renders App + all children
  return <><SearchBox value={search} onChange={setSearch} /><HeavyList /></>
}

// GOOD: colocate state with the components that need it
function SearchBox() {
  const [search, setSearch] = useState('')  // only SearchBox re-renders
  return <input value={search} onChange={e => setSearch(e.target.value)} />
}

Context Splitting

// BAD: one context causes all consumers to re-render on any change
const AppContext = createContext({ user, theme, cart, notifications })

// GOOD: split contexts by change frequency
const UserContext    = createContext<User | null>(null)
const ThemeContext   = createContext<Theme>('light')
const CartContext    = createContext<Cart>({ items: [] })

Lazy Loading

import { lazy, Suspense, startTransition } from 'react'

const HeavyEditor = lazy(() => import('./HeavyEditor'))

function App() {
  const [showEditor, setShowEditor] = useState(false)

  // startTransition: mark as non-urgent (don't block urgent UI updates)
  const openEditor = () => startTransition(() => setShowEditor(true))

  return (
    <>
      <button onClick={openEditor}>Open Editor</button>
      {showEditor && (
        <Suspense fallback={<EditorSkeleton />}>
          <HeavyEditor />
        </Suspense>
      )}
    </>
  )
}

Concurrent Features

// useDeferredValue: defer non-urgent rendering
function SearchResults({ query }: { query: string }) {
  const deferredQuery = useDeferredValue(query)
  const isStale = query !== deferredQuery

  return (
    <div style={{ opacity: isStale ? 0.5 : 1 }}>
      <Suspense fallback={<Spinner />}>
        <Results query={deferredQuery} />
      </Suspense>
    </div>
  )
}

// useTransition: mark state update as non-urgent
function TabBar() {
  const [isPending, startTransition] = useTransition()
  const [tab, setTab] = useState('home')

  return (
    <>
      {tabs.map(t => (
        <button
          key={t}
          onClick={() => startTransition(() => setTab(t))}
          disabled={isPending}
        >
          {t}
        </button>
      ))}
      <Suspense fallback={<Spinner />}>
        <TabContent tab={tab} />
      </Suspense>
    </>
  )
}

Bundle Optimization

// Dynamic import for conditional heavy deps
async function exportToPDF() {
  const { jsPDF } = await import('jspdf')  // loaded only when needed
  const doc = new jsPDF()
  doc.save('report.pdf')
}

// Tree-shaking: named imports from specific sub-paths
import { format } from 'date-fns/format'           // not 'date-fns'
import { debounce } from 'lodash-es/debounce'       // not 'lodash'

Image & Asset Performance

// next/image with blur placeholder
import Image from 'next/image'

<Image
  src={product.imageUrl}
  alt={product.name}
  width={400}
  height={300}
  sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 400px"
  placeholder="blur"
  blurDataURL={product.blurHash}
/>

Keys & Reconciliation

// BAD: index as key causes incorrect reconciliation on reorder/insert
{items.map((item, i) => <Item key={i} item={item} />)}

// GOOD: stable unique ID
{items.map(item => <Item key={item.id} item={item} />)}

// Intentional reset via key (new key = new component instance)
<ExpensiveForm key={userId} userId={userId} />

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.