React performance
Skill sairam0424/MindForge/.mindforge/skills/react-performance
MindForge: The Enterprise Agentic Framework for Claude Code & Antigravity. High-performance autonomous execution, wave-parallelism, and multi-tier governance for production-grade AI engineering.From the repository description
npx -y skills add sairam0424/MindForge --skill react-performanceAssembled 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
9.1 KB, ~2.1k tokens by cl100k_base, as published. Nobody here has run it
Skill — React Performance
When this skill activates
Any task involving React application performance: reducing unnecessary re-renders, optimizing bundle size, implementing code splitting, virtualizing long lists, profiling component render times, or improving Core Web Vitals in React apps.
Mandatory actions when this skill is active
Before writing any code
- Identify the performance problem with measurement. Do not guess.
- Use React DevTools Profiler to record interactions and identify slow renders.
- Use the browser Performance tab to measure paint times and long tasks.
- Use
webpack-bundle-analyzeror@next/bundle-analyzerto identify large chunks.
- Determine the category of problem:
- Unnecessary re-renders (component renders without visual change)
- Large bundle size (initial JS payload too big)
- Long lists without virtualization (DOM thrashing)
- Expensive computations on every render
- Layout thrashing (forced synchronous reflows)
- Set a measurable target before optimizing:
- LCP target (e.g., < 2.5s)
- Bundle size budget (e.g., initial JS < 200KB gzipped)
- Interaction latency (e.g., click-to-render < 100ms)
During implementation
Identifying Re-renders
- Install
@welldone-software/why-did-you-renderin development:// wdyr.ts (import before React) import React from "react"; if (process.env.NODE_ENV === "development") { const whyDidYouRender = require("@welldone-software/why-did-you-render"); whyDidYouRender(React, { trackAllPureComponents: true }); } - Use React DevTools Profiler "Highlight updates" to visually see which components re-render.
- A re-render is wasteful ONLY if:
- The component's output is identical to the previous render, AND
- The render takes meaningful time (> 1ms measured in Profiler).
React.memo
- When to use: Component receives the same props frequently AND its render is expensive (> 5ms).
- When NOT to use: Simple components (< 1ms render), components that always receive new props.
- Implementation pattern:
const ExpensiveList = React.memo(function ExpensiveList({ items, onSelect }: Props) { // expensive render logic return <ul>{items.map(item => <ListItem key={item.id} item={item} onSelect={onSelect} />)}</ul>; }); - Custom comparison for complex props:
const MemoizedChart = React.memo(ChartComponent, (prev, next) => { return prev.data.length === next.data.length && prev.data[0]?.id === next.data[0]?.id; });
useMemo and useCallback
- Rule: Do NOT add these by default. Add them ONLY when profiling shows a problem.
- useMemo — use when:
- Computing derived data that is expensive (> 1ms) on every render
- Passing a computed object/array to a memoized child (reference stability)
const sortedItems = useMemo( () => items.toSorted((a, b) => a.name.localeCompare(b.name)), [items] ); - useCallback — use when:
- Passing a callback to a memoized child component
- The callback is used as a dependency in a child's useEffect
const handleSelect = useCallback((id: string) => { setSelected(id); }, []); - Never use for: Simple event handlers on non-memoized elements, values that change every render anyway.
Code Splitting
- Split at the route level (every page is a separate chunk):
const Dashboard = lazy(() => import("./pages/Dashboard")); const Settings = lazy(() => import("./pages/Settings")); function App() { return ( <Suspense fallback={<PageSkeleton />}> <Routes> <Route path="/dashboard" element={<Dashboard />} /> <Route path="/settings" element={<Settings />} /> </Routes> </Suspense> ); } - Split heavy libraries used in specific features:
const ChartModule = lazy(() => import("./components/ChartModule")); // Only loaded when user navigates to analytics - Use named webpack chunks for debugging:
import(/* webpackChunkName: "chart" */ "./Chart"). - Prefetch likely-next routes on hover/focus:
const prefetchDashboard = () => import("./pages/Dashboard"); <Link onMouseEnter={prefetchDashboard} to="/dashboard">Dashboard</Link>
Virtualization (Long Lists)
- Use virtualization when rendering > 50 items in a scrollable container.
- Libraries:
@tanstack/react-virtual(recommended),react-window,react-virtuoso. - Implementation pattern:
import { useVirtualizer } from "@tanstack/react-virtual"; function VirtualList({ items }: { items: Item[] }) { const parentRef = useRef<HTMLDivElement>(null); const virtualizer = useVirtualizer({ count: items.length, getScrollElement: () => parentRef.current, estimateSize: () => 48, // estimated row height in px overscan: 5, // render 5 extra items above/below viewport }); return ( <div ref={parentRef} style={{ height: "600px", overflow: "auto" }}> <div style={{ height: `${virtualizer.getTotalSize()}px`, position: "relative" }}> {virtualizer.getVirtualItems().map(virtualRow => ( <div key={virtualRow.key} style={{ position: "absolute", top: 0, transform: `translateY(${virtualRow.start}px)`, height: `${virtualRow.size}px`, width: "100%", }} > <ListRow item={items[virtualRow.index]} /> </div> ))} </div> </div> ); } - For grids, use the grid virtualizer variant.
- Always provide
estimateSizeclose to actual size to avoid layout jumps.
Bundle Analysis
- Generate and inspect the bundle:
# Next.js ANALYZE=true next build # Vite npx vite-bundle-visualizer # Webpack npx webpack --profile --json > stats.json npx webpack-bundle-analyzer stats.json - Common wins:
- Replace
momentwithdate-fnsordayjs(save ~200KB). - Replace
lodashwith individual imports:import groupBy from "lodash/groupBy". - Use dynamic import for heavy deps used in one feature (chart libs, PDF generators).
- Ensure tree-shaking: use ESM imports, check
sideEffectsin package.json. - Remove unused dependencies:
npx depcheck.
- Replace
Image Optimization
- Use
next/image(Next.js) or manual<img loading="lazy" decoding="async">. - Serve WebP/AVIF with
<picture>fallback for older browsers. - Always specify
widthandheightto prevent CLS. - Use responsive
srcsetfor different viewport sizes. - Lazy load images below the fold; eager load the LCP image.
State Management Performance
- Colocate state: keep state as close to where it is used as possible.
- Split context providers: one large context triggers re-renders on every consumer for any state change. Split into focused providers.
- Use selector patterns (
useSelector, Zustand selectors) to subscribe to slices:// Zustand: only re-renders when count changes const count = useStore(state => state.count); - Avoid putting frequently-changing values (mouse position, scroll offset) in React state. Use refs or external stores.
After implementation
- Re-profile with React DevTools Profiler and compare flamegraphs.
- Run Lighthouse and compare scores (LCP, INP, CLS, Total Blocking Time).
- Verify bundle sizes with analyzer: confirm the target budget is met.
- Test on a throttled device (Chrome DevTools: 4x CPU slowdown, Slow 3G) to validate the optimization matters in realistic conditions.
- Ensure no visual regressions: the UI must look and behave identically.
React performance anti-patterns to flag
useMemo/useCallbackon every single function (adds overhead without benefit).- Inline object/array literals as props to memoized components (defeats memo).
- Storing derived state that could be computed from existing state/props.
- Re-creating context providers on every render (move value computation to useMemo).
- Using
indexas key in lists that reorder (causes incorrect reconciliation). - Fetching data inside components without caching (use SWR, React Query, or similar).
- Rendering 1000+ DOM nodes without virtualization.
Self-check before task completion
Before marking a task done when this skill was active:
- Performance problem was identified with profiling tools (not guessed).
- Measurable improvement demonstrated (before/after numbers).
- No unnecessary memoization added (each memo justified by measurement).
- Bundle size budget verified with analyzer.
- No visual or functional regressions introduced.
- Optimizations tested on throttled device conditions.
- Core Web Vitals (LCP, INP, CLS) meet targets.
- Code splitting applied at route level minimum.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.