react-performance — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited react-performance (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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.
webpack-bundle-analyzer or @next/bundle-analyzer to identify large chunks.#### Identifying Re-renders
@welldone-software/why-did-you-render in 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 });
}#### React.memo
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>;
}); 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
const sortedItems = useMemo(
() => items.toSorted((a, b) => a.name.localeCompare(b.name)),
[items]
); const handleSelect = useCallback((id: string) => {
setSelected(id);
}, []);#### Code Splitting
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>
);
} const ChartModule = lazy(() => import("./components/ChartModule"));
// Only loaded when user navigates to analyticsimport(/* webpackChunkName: "chart" */ "./Chart"). const prefetchDashboard = () => import("./pages/Dashboard");
<Link onMouseEnter={prefetchDashboard} to="/dashboard">Dashboard</Link>#### Virtualization (Long Lists)
@tanstack/react-virtual (recommended), react-window, react-virtuoso. 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>
);
}estimateSize close to actual size to avoid layout jumps.#### Bundle Analysis
# Next.js
ANALYZE=true next build
# Vite
npx vite-bundle-visualizer
# Webpack
npx webpack --profile --json > stats.json
npx webpack-bundle-analyzer stats.jsonmoment with date-fns or dayjs (save ~200KB).lodash with individual imports: import groupBy from "lodash/groupBy".sideEffects in package.json.npx depcheck.#### Image Optimization
next/image (Next.js) or manual <img loading="lazy" decoding="async">.<picture> fallback for older browsers.width and height to prevent CLS.srcset for different viewport sizes.#### State Management Performance
for any state change. Split into focused providers.
useSelector, Zustand selectors) to subscribe to slices: // Zustand: only re-renders when count changes
const count = useStore(state => state.count);Use refs or external stores.
the optimization matters in realistic conditions.
useMemo/useCallback on every single function (adds overhead without benefit).index as key in lists that reorder (causes incorrect reconciliation).Before marking a task done when this skill was active:
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.