gh-Dimillian-Skills/react-component-performance/SKILL.md
Alan Pope 3db84e63d0
feat: improve 8 skills with targeted optimizations
Hullo @dimillian 👋

I ran your skills through `tessl skill review` at work and found some targeted improvements. Here's the before/after:

| Skill | Before | After | Change |
|-------|--------|-------|--------|
| swiftui-ui-patterns | 81% | 100% | +19% |
| github | 85% | 100% | +15% |
| macos-spm-app-packaging | 86% | 100% | +14% |
| react-component-performance | 86% | 100% | +14% |
| swift-concurrency-expert | 88% | 100% | +12% |
| app-store-changelog | 93% | 100% | +7% |
| ios-debugger-agent | 94% | 100% | +6% |
| swiftui-view-refactor | 93% | 95% | +2% |
| swiftui-liquid-glass | 100% | 100% | — |
| swiftui-performance-audit | 100% | 100% | — |

<details>
<summary>Changes made</summary>

**swiftui-ui-patterns** — Expanded description with additional trigger terms (VStack/HStack, @State, @Binding, navigation hierarchies, custom view modifiers). Added explicit build validation checkpoints and error recovery guidance to the workflow steps.

**github** — Added explicit "Use when..." clause with natural trigger terms (check CI status, create PR, list issues). Added a structured "Debugging a CI Failure" numbered workflow organizing existing commands into a clear investigation sequence.

**macos-spm-app-packaging** — Added a minimum end-to-end example (bootstrap to running app). Added validation checkpoints after packaging, signing, and notarization with specific verification commands (codesign, spctl, stapler). Added a common notarization failures troubleshooting table.

**react-component-performance** — Added three concrete before/after code examples (isolate ticking state, stabilize callbacks with useCallback + memo, derived data with useMemo). Expanded profiling validation with explicit React DevTools Profiler steps.

**swift-concurrency-expert** — Expanded description with concrete actions (adding Sendable conformance, @MainActor annotations, resolving actor isolation warnings). Added verification step to workflow. Added three before/after Swift code examples covering @MainActor, protocol conformance isolation, and @concurrent.

**app-store-changelog** — Added commit-to-bullet transformation examples showing how raw commits map to user-facing App Store bullets, plus examples of internal-only commits that get dropped. Added a complete example "What's New" output block.

**ios-debugger-agent** — Added build failure handling and post-launch verification checkpoints to the core workflow (verify app launched via describe_ui or screenshot before proceeding to UI interaction).

**swiftui-view-refactor** — Tightened prose in sections 3, 3b, and large-view handling. Removed a redundant example. Converted workflow list to clean numbered format.

</details>

Honest disclosure — I work at @tesslio where we build tooling around skills like these. Not a pitch - just saw room for improvement and wanted to contribute.

If you want to run reviews, evals and optimizations yourself, just `npm install @tessl/cli` then run `tessl skill review path/to/your/SKILL.md`, and click here (https://tessl.io/registry/skills/submit) to find out more.

Thanks in advance 🙏
2026-03-06 16:53:32 +00:00

127 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: react-component-performance
description: Analyze and optimize React component performance issues (slow renders, re-render thrash, laggy lists, expensive computations). Use when asked to profile or improve a React component, reduce re-renders, or speed up UI updates in React apps.
---
# React Component Performance
## Overview
Identify render hotspots, isolate expensive updates, and apply targeted optimizations without changing UI behavior.
## Workflow
1. Reproduce or describe the slowdown.
2. Identify what triggers re-renders (state updates, props churn, effects).
3. Isolate fast-changing state from heavy subtrees.
4. Stabilize props and handlers; memoize where it pays off.
5. Reduce expensive work (computation, DOM size, list length).
6. **Validate**: open React DevTools Profiler → record the interaction → inspect the Flamegraph for components rendering longer than ~16 ms → compare against a pre-optimization baseline recording.
## Checklist
- Measure: use React DevTools Profiler or log renders; capture baseline.
- Find churn: identify state updated on a timer, scroll, input, or animation.
- Split: move ticking state into a child; keep heavy lists static.
- Memoize: wrap leaf rows with `memo` only when props are stable.
- Stabilize props: use `useCallback`/`useMemo` for handlers and derived values.
- Avoid derived work in render: precompute, or compute inside memoized helpers.
- Control list size: window/virtualize long lists; avoid rendering hidden items.
- Keys: ensure stable keys; avoid index when order can change.
- Effects: verify dependency arrays; avoid effects that re-run on every render.
- Style/layout: watch for expensive layout thrash or large Markdown/diff renders.
## Optimization Patterns
### Isolate ticking state
Move a timer or animation counter into a child so the parent list never re-renders on each tick.
```tsx
// ❌ Before entire parent (and list) re-renders every second
function Dashboard({ items }: { items: Item[] }) {
const [tick, setTick] = useState(0);
useEffect(() => {
const id = setInterval(() => setTick(t => t + 1), 1000);
return () => clearInterval(id);
}, []);
return (
<>
<Clock tick={tick} />
<ExpensiveList items={items} /> {/* re-renders every second */}
</>
);
}
// ✅ After only <Clock> re-renders; list is untouched
function Clock() {
const [tick, setTick] = useState(0);
useEffect(() => {
const id = setInterval(() => setTick(t => t + 1), 1000);
return () => clearInterval(id);
}, []);
return <span>{tick}s</span>;
}
function Dashboard({ items }: { items: Item[] }) {
return (
<>
<Clock />
<ExpensiveList items={items} />
</>
);
}
```
### Stabilize callbacks with `useCallback` + `memo`
```tsx
// ❌ Before new handler reference on every render busts Row memo
function List({ items }: { items: Item[] }) {
const handleClick = (id: string) => console.log(id); // new ref each render
return items.map(item => <Row key={item.id} item={item} onClick={handleClick} />);
}
// ✅ After stable handler; Row only re-renders when its own item changes
const Row = memo(({ item, onClick }: RowProps) => (
<li onClick={() => onClick(item.id)}>{item.name}</li>
));
function List({ items }: { items: Item[] }) {
const handleClick = useCallback((id: string) => console.log(id), []);
return items.map(item => <Row key={item.id} item={item} onClick={handleClick} />);
}
```
### Prefer derived data outside render
```tsx
// ❌ Before recomputes on every render
function Summary({ orders }: { orders: Order[] }) {
const total = orders.reduce((sum, o) => sum + o.amount, 0); // runs every render
return <p>Total: {total}</p>;
}
// ✅ After recomputes only when orders changes
function Summary({ orders }: { orders: Order[] }) {
const total = useMemo(() => orders.reduce((sum, o) => sum + o.amount, 0), [orders]);
return <p>Total: {total}</p>;
}
```
### Additional patterns
- **Split rows**: extract list rows into memoized components with narrow props.
- **Defer heavy rendering**: lazy-render or collapse expensive content until expanded.
## Profiling Validation Steps
1. Open **React DevTools → Profiler** tab.
2. Click **Record**, perform the slow interaction, then **Stop**.
3. Switch to **Flamegraph** view; any bar labeled with a component and time > ~16 ms is a candidate.
4. Use **Ranked chart** to sort by self render time and target the top offenders.
5. Apply one optimization at a time, re-record, and compare render counts and durations against the baseline.
## Example Reference
Load `references/examples.md` when the user wants a concrete refactor example.