skills/react-best-practices/SKILL.md
Vercel Engineering's React & Next.js performance optimization guide. Use when writing React components, implementing data fetching, reviewing code for performance, refactoring, or optimizing bundle size. Contains 40+ rules across 8 priority categories.
npx skillsauth add excatt/superclaude-plusplus react-best-practicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Comprehensive performance optimization guide for React and Next.js applications, maintained by Vercel Engineering. Contains 40+ rules across 8 categories prioritized by impact.
Reference these guidelines when:
Required Rule: Use pnpm (npm, yarn forbidden)
| Item | Rule |
|------|------|
| Package Manager | pnpm (mandatory) |
| Lock File | pnpm-lock.yaml (must commit) |
| Workspace | pnpm-workspace.yaml (monorepo) |
# ✅ Correct
pnpm add react next
pnpm add -D typescript @types/react
pnpm install --frozen-lockfile
# ❌ Incorrect
npm install react next
yarn add react next
# ✅ Correct - pnpm in Docker
FROM node:20-slim
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --prod
COPY . .
CMD ["pnpm", "start"]
# ✅ Correct - pnpm in CI
- uses: pnpm/action-setup@v2
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- run: pnpm test
- run: pnpm build
Detection: Suggest migration to pnpm if package-lock.json or yarn.lock found
Impact: 2-10x performance improvement
Move await statements to where the data is actually needed.
// ❌ Incorrect - blocks entire function
async function Page() {
const data = await fetchData();
const user = await fetchUser();
return <Component data={data} user={user} />;
}
// ✅ Correct - parallel fetching
async function Page() {
const dataPromise = fetchData();
const userPromise = fetchUser();
return <Component dataPromise={dataPromise} userPromise={userPromise} />;
}
Execute independent operations concurrently.
// ❌ Incorrect - sequential
const users = await getUsers();
const posts = await getPosts();
const comments = await getComments();
// ✅ Correct - parallel
const [users, posts, comments] = await Promise.all([
getUsers(),
getPosts(),
getComments()
]);
Use better-all for operations with complex dependencies.
import { all } from 'better-all';
// ✅ Correct - handles dependencies automatically
const { user, posts, notifications } = await all({
user: () => fetchUser(userId),
posts: ({ user }) => fetchPosts(user.id),
notifications: ({ user }) => fetchNotifications(user.id)
});
Deploy Suspense boundaries for faster initial paint.
// ✅ Correct - progressive loading
function Page() {
return (
<div>
<Header /> {/* Renders immediately */}
<Suspense fallback={<Skeleton />}>
<SlowContent /> {/* Streams in when ready */}
</Suspense>
</div>
);
}
Impact: 200-800ms faster load times
Use direct source imports instead of barrel files.
// ❌ Incorrect - imports entire barrel
import { Button } from '@/components';
import { formatDate } from '@/utils';
// ✅ Correct - direct imports
import { Button } from '@/components/Button';
import { formatDate } from '@/utils/formatDate';
Lazy-load components that aren't immediately needed.
import dynamic from 'next/dynamic';
// ✅ Correct - lazy load heavy component
const HeavyChart = dynamic(() => import('./HeavyChart'), {
loading: () => <ChartSkeleton />,
ssr: false // Skip SSR for client-only components
});
Load non-critical scripts after hydration.
import Script from 'next/script';
// ✅ Correct - deferred loading
<Script
src="https://analytics.example.com/script.js"
strategy="lazyOnload"
/>
Load modules only when features are active.
// ✅ Correct - load only when needed
async function handleAdvancedFeature() {
const { advancedFunction } = await import('./advancedModule');
return advancedFunction();
}
Preload bundles based on user intent.
// ✅ Correct - preload on hover
function NavLink({ href, children }) {
const handleMouseEnter = () => {
import(`./pages${href}`); // Preload the route
};
return (
<Link href={href} onMouseEnter={handleMouseEnter}>
{children}
</Link>
);
}
Deduplicate data fetching within a single request.
import { cache } from 'react';
// ✅ Correct - cached per request
export const getUser = cache(async (id: string) => {
return await db.user.findUnique({ where: { id } });
});
Cache expensive computations across requests.
import { LRUCache } from 'lru-cache';
const cache = new LRUCache<string, any>({ max: 500 });
// ✅ Correct - cross-request cache
export async function getExpensiveData(key: string) {
if (cache.has(key)) return cache.get(key);
const data = await computeExpensive(key);
cache.set(key, data);
return data;
}
Reduce data passed across RSC boundaries.
// ❌ Incorrect - passes entire object
<ClientComponent user={fullUserObject} />
// ✅ Correct - minimal data
<ClientComponent
userName={user.name}
userAvatar={user.avatar}
/>
Structure components to enable parallel fetching.
// ✅ Correct - parallel through composition
function Page() {
return (
<>
<UserSection userId={id} /> {/* fetches user */}
<PostsSection userId={id} /> {/* fetches posts in parallel */}
<CommentsSection postId={pid} /> {/* fetches comments in parallel */}
</>
);
}
Schedule operations that don't block the response.
import { after } from 'next/server';
// ✅ Correct - non-blocking analytics
export async function GET() {
const data = await fetchData();
after(() => {
logAnalytics(data); // Runs after response sent
});
return Response.json(data);
}
Use SWR for client-side data fetching with built-in deduplication.
import useSWR from 'swr';
// ✅ Correct - deduplicated across components
function useUser(id: string) {
return useSWR(`/api/user/${id}`, fetcher);
}
Deduplicate global event listeners.
import useSWRSubscription from 'swr/subscription';
// ✅ Correct - single listener, shared state
function useOnlineStatus() {
return useSWRSubscription('online-status', (key, { next }) => {
const handler = () => next(null, navigator.onLine);
window.addEventListener('online', handler);
window.addEventListener('offline', handler);
return () => {
window.removeEventListener('online', handler);
window.removeEventListener('offline', handler);
};
});
}
Read state at the point of use, not at the top of components.
// ❌ Incorrect - reads at top, re-renders entire tree
function Parent() {
const count = useStore(state => state.count);
return <Child count={count} />;
}
// ✅ Correct - reads where needed
function Parent() {
return <Child />;
}
function Child() {
const count = useStore(state => state.count);
return <span>{count}</span>;
}
Isolate expensive renders.
// ✅ Correct - isolated expensive render
const ExpensiveList = memo(function ExpensiveList({ items }) {
return items.map(item => <ExpensiveItem key={item.id} item={item} />);
});
function Parent({ items, otherState }) {
return (
<div>
<ExpensiveList items={items} />
<CheapComponent state={otherState} />
</div>
);
}
Use primitives instead of objects in dependency arrays.
// ❌ Incorrect - object reference changes
useEffect(() => {
fetchData(user);
}, [user]);
// ✅ Correct - stable primitive
useEffect(() => {
fetchData(userId);
}, [userId]);
Prevent stale closures with functional updates.
// ❌ Incorrect - may use stale count
setCount(count + 1);
// ✅ Correct - always uses current value
setCount(prev => prev + 1);
Defer expensive initial state computation.
// ❌ Incorrect - runs every render
const [data, setData] = useState(expensiveComputation());
// ✅ Correct - runs once
const [data, setData] = useState(() => expensiveComputation());
Use transitions for non-critical updates.
import { useTransition } from 'react';
function SearchResults() {
const [isPending, startTransition] = useTransition();
const handleSearch = (query) => {
startTransition(() => {
setSearchResults(filterResults(query));
});
};
}
Move static elements outside components.
// ✅ Correct - static JSX hoisted
const StaticHeader = <header><h1>Welcome</h1></header>;
function Page() {
return (
<div>
{StaticHeader}
<DynamicContent />
</div>
);
}
Apply CSS containment for off-screen content.
/* ✅ Correct - skip rendering off-screen items */
.list-item {
content-visibility: auto;
contain-intrinsic-size: 0 50px;
}
Use Activity (or custom equivalent) for frequently shown/hidden content.
// ✅ Correct - preserves state, skips unmount/remount
<Activity mode={isVisible ? 'visible' : 'hidden'}>
<ExpensiveComponent />
</Activity>
Animate wrapper elements for better performance.
// ✅ Correct - hardware acceleration
<motion.div animate={{ x: 100 }}>
<svg>{/* static SVG content */}</svg>
</motion.div>
Use ternary operators for clearer render paths.
// ❌ Incorrect - implicit falsy render
{items.length && <List items={items} />}
// ✅ Correct - explicit conditional
{items.length > 0 ? <List items={items} /> : null}
Replace repeated array searches with Map lookups.
// ❌ Incorrect - O(n) per lookup
const user = users.find(u => u.id === targetId);
// ✅ Correct - O(1) lookup
const userMap = new Map(users.map(u => [u.id, u]));
const user = userMap.get(targetId);
O(1) instead of O(n) for includes checks.
// ❌ Incorrect - O(n)
if (allowedIds.includes(id)) { }
// ✅ Correct - O(1)
const allowedSet = new Set(allowedIds);
if (allowedSet.has(id)) { }
Avoid repeated property lookups.
// ❌ Incorrect - repeated access
for (let i = 0; i < arr.length; i++) {
process(obj.nested.value);
}
// ✅ Correct - cached access
const { length } = arr;
const { value } = obj.nested;
for (let i = 0; i < length; i++) {
process(value);
}
Use classes or cssText for multiple style changes.
// ❌ Incorrect - multiple reflows
el.style.width = '100px';
el.style.height = '100px';
el.style.margin = '10px';
// ✅ Correct - single reflow
el.classList.add('active-state');
// or
el.style.cssText = 'width:100px;height:100px;margin:10px';
Avoid recreating RegExp on every render.
// ❌ Incorrect - creates new RegExp each render
function Component({ value }) {
const isValid = /^[a-z]+$/.test(value);
}
// ✅ Correct - single instance
const ALPHA_REGEX = /^[a-z]+$/;
function Component({ value }) {
const isValid = ALPHA_REGEX.test(value);
}
Exit functions early when possible.
// ✅ Correct - early return pattern
function processUser(user) {
if (!user) return null;
if (!user.active) return null;
return performExpensiveOperation(user);
}
Avoid mutating original arrays.
// ❌ Incorrect - mutates original
const sorted = items.sort((a, b) => a.id - b.id);
// ✅ Correct - returns new array
const sorted = items.toSorted((a, b) => a.id - b.id);
Stable subscriptions without effect re-runs.
// ✅ Correct - stable callback reference
const callbackRef = useRef(callback);
callbackRef.current = callback;
useEffect(() => {
return subscribe(() => callbackRef.current());
}, []); // Empty deps - never re-subscribes
Access latest values without re-running effects.
// ✅ Correct - stable effect with fresh values
const onTick = useEffectEvent(() => {
logCurrentState(state); // Always has latest state
});
useEffect(() => {
const id = setInterval(onTick, 1000);
return () => clearInterval(id);
}, []); // Never re-creates interval
React Compiler: Some optimizations (memo, useMemo hoisting) are handled automatically by React Compiler when enabled.
Measure First: Apply optimizations based on measured bottlenecks, not assumptions.
Context Matters: Pattern selection depends on specific use cases and trade-offs.
Progressive Enhancement: Start with critical optimizations (Priority 1-2) before lower priorities.
testing
사용자 계획을 기존 도메인 모델에 대해 stress-test하는 인터뷰 세션. 용어를 날카롭게 다듬고, 결정이 굳어질 때마다 CONTEXT.md(도메인 어휘 사전)와 ADR을 인라인으로 갱신한다. 새 기능 요구사항 탐색은 `/brainstorm`을, 기존 도메인 모델·용어와의 정합성 점검은 이 스킬을 사용한다.
development
# Excel (XLSX) Spreadsheet Skill Claude Code supports comprehensive spreadsheet operations through the **xlsx** skill, enabling creation, editing, and analysis of Excel files (.xlsx, .xlsm, .csv, .tsv). ## Trigger - When user needs Excel spreadsheet creation or editing - Financial modeling or data analysis required - Spreadsheet formulas and calculations needed - Data import from CSV/TSV files ## Core Capabilities **Primary functions include:** - Creating new spreadsheets with formulas and f
tools
Generate structured implementation workflows from PRDs and feature requirements
development
실시간 통신 설계 가이드를 실행합니다.