home / skills / yonatangross / orchestkit / render-optimization

render-optimization skill

/plugins/ork/skills/render-optimization

This skill helps you optimize React render performance by leveraging the compiler, profiling, virtualization, and targeted memoization strategies.

npx playbooks add skill yonatangross/orchestkit --skill render-optimization

Review the files below or copy the command above to add this skill to your agents.

Files (9)
SKILL.md
4.2 KB
---
name: render-optimization
description: React render performance patterns including React Compiler integration, memoization strategies, TanStack Virtual, and DevTools profiling. Use when debugging slow renders, optimizing large lists, or reducing unnecessary re-renders.
context: fork
agent: frontend-ui-developer
version: 1.0.0
tags: [react, performance, optimization, react-compiler, virtualization, memo, profiler]
user-invocable: false
---

# React Render Optimization

Modern render performance patterns for React 19+.

## Decision Tree: React Compiler First (2026)

```
Is React Compiler enabled?
├─ YES → Let compiler handle memoization automatically
│        Only use useMemo/useCallback as escape hatches
│        DevTools shows "Memo ✨" badge
│
└─ NO → Profile first, then optimize
         1. React DevTools Profiler
         2. Identify actual bottlenecks
         3. Apply targeted optimizations
```

## React Compiler (Primary Approach)

React 19's compiler automatically memoizes:
- Component re-renders
- Intermediate values (like useMemo)
- Callback references (like useCallback)
- JSX elements

```tsx
// next.config.js (Next.js 16+)
const nextConfig = {
  reactCompiler: true,
}

// Expo SDK 54+ enables by default
```

**Verification**: Open React DevTools → Look for "Memo ✨" badge

## When Manual Memoization Still Needed

Use `useMemo`/`useCallback` as escape hatches when:

```tsx
// 1. Effect dependencies that shouldn't trigger re-runs
const stableConfig = useMemo(() => ({
  apiUrl: process.env.API_URL
}), [])

useEffect(() => {
  initializeSDK(stableConfig)
}, [stableConfig])

// 2. Third-party libraries without compiler support
const memoizedValue = useMemo(() =>
  expensiveThirdPartyComputation(data), [data])

// 3. Precise control over memoization boundaries
const handleClick = useCallback(() => {
  // Critical callback that must be stable
}, [dependency])
```

## Virtualization Thresholds

| Item Count | Recommendation |
|------------|----------------|
| < 100 | Regular rendering usually fine |
| 100-500 | Consider virtualization |
| 500+ | Virtualization required |

```tsx
import { useVirtualizer } from '@tanstack/react-virtual'

const virtualizer = useVirtualizer({
  count: items.length,
  getScrollElement: () => parentRef.current,
  estimateSize: () => 50,
  overscan: 5,
})
```

## State Colocation

Move state as close to where it's used as possible:

```tsx
// ❌ State too high - causes unnecessary re-renders
function App() {
  const [filter, setFilter] = useState('')
  return (
    <Header />  {/* Re-renders on filter change! */}
    <FilterInput value={filter} onChange={setFilter} />
    <List filter={filter} />
  )
}

// ✅ State colocated - minimal re-renders
function App() {
  return (
    <Header />
    <FilterableList />  {/* State inside */}
  )
}
```

## Profiling Workflow

1. **React DevTools Profiler**: Record, interact, analyze
2. **Identify**: Components with high render counts or duration
3. **Verify**: Is the re-render actually causing perf issues?
4. **Fix**: Apply targeted optimization
5. **Measure**: Confirm improvement

## Quick Wins

1. **Key prop**: Stable, unique keys for lists
2. **Lazy loading**: `React.lazy()` for code splitting
3. **Debounce**: Input handlers with `useDeferredValue`
4. **Suspense**: Streaming with proper boundaries

## Key Decisions

| Decision | Recommendation |
|----------|----------------|
| Memoization | Let React Compiler handle it (2026 default) |
| Lists 100+ items | Use TanStack Virtual |
| State placement | Colocate as close to usage as possible |
| Profiling | Always measure before optimizing |

## Related Skills

- `react-server-components-framework` - Server-first rendering
- `vite-advanced` - Build optimization
- `e2e-testing` - Performance testing with Playwright

## References

- [React Compiler Migration](references/react-compiler-migration.md) - Compiler adoption
- [Memoization Escape Hatches](references/memoization-escape-hatches.md) - When useMemo needed
- [TanStack Virtual](references/tanstack-virtual-patterns.md) - Virtualization
- [State Colocation](references/state-colocation.md) - State placement
- [DevTools Profiler](references/devtools-profiler-workflow.md) - Finding bottlenecks

Overview

This skill provides practical patterns for improving React 19+ render performance, combining React Compiler guidance, targeted memoization, TanStack Virtual for large lists, and DevTools-driven profiling. It focuses on measurable outcomes: fewer unnecessary re-renders, smoother large-list scrolling, and faster interaction latencies.

How this skill works

It inspects render behavior using a profiling-first workflow and recommends optimizations based on whether the React Compiler is enabled. When the compiler is active, the skill advises treating it as the primary memoization layer and using manual memoization only as an escape hatch. For heavy lists it prescribes TanStack Virtual and gives thresholds and code snippets to implement virtualization and colocate state to reduce render scope.

When to use it

  • You see high render counts or long render durations in React DevTools Profiler
  • Large lists or tables (100+ items) causing janky scrolling
  • You need to prevent unnecessary parent-to-child re-renders
  • Migrating to React Compiler or verifying its benefits
  • Tuning third-party components that re-render frequently

Best practices

  • Profile first with React DevTools; measure before changing code
  • Enable React Compiler where possible and rely on its memoization
  • Use useMemo/useCallback only as escape hatches for effect dependencies, third-party APIs, or precise stability needs
  • Colocate state near the components that use it to minimize propagation
  • Apply TanStack Virtual for lists beyond 100 items, required for 500+
  • Use stable keys, lazy loading, useDeferredValue for inputs, and Suspense boundaries for streaming

Example use cases

  • A feed component with 1,000 items: add TanStack Virtual and stable keys to restore smooth scroll
  • An app migrating to React Compiler: enable compiler and remove redundant useMemo calls, then verify 'Memo ✨' in DevTools
  • Debugging a dashboard: profile to find a parent re-rendering many children, then colocate the state to the child
  • A third-party chart re-computing on every frame: wrap expensive computation in useMemo with correct dependencies
  • Reducing UI lag for rapid input: debounce updates using useDeferredValue and measure before/after

FAQ

If I enable the React Compiler, do I need useMemo/useCallback?

Usually no. The compiler auto-memoizes many patterns. Keep useMemo/useCallback as escape hatches for effect stability, unsupported third-party code, or when you need an explicit memo boundary.

When should I add virtualization for a list?

Start considering virtualization around 100 items; strongly use it at 500+ items. Measure the scroll performance and memory before committing.