react
Core React 19 patterns including hooks, Suspense, lazy loading, component structure, TypeScript best practices, and performance optimization. Use when working with React components, hooks, lazy loading, Suspense boundaries, or React-specific TypeScript patterns.
$ 설치
git clone https://github.com/blencorp/claude-code-kit /tmp/claude-code-kit && cp -r /tmp/claude-code-kit/cli/kits/react/skills/react ~/.claude/skills/claude-code-kit// tip: Run this command in your terminal to install the skill
SKILL.md
name: react description: Core React 19 patterns including hooks, Suspense, lazy loading, component structure, TypeScript best practices, and performance optimization. Use when working with React components, hooks, lazy loading, Suspense boundaries, or React-specific TypeScript patterns.
React Core Patterns
Purpose
Essential React 19 patterns for building modern applications with hooks, Suspense, lazy loading, and TypeScript.
Note: React 19 (released December 2024) breaking changes:
forwardRefno longer needed - passrefas a prop directlypropTypesremoved (silently ignored)- New JSX transform required
React.FCtype discouraged - use direct function components instead
When to Use This Skill
- Creating React components
- Using React hooks (useState, useEffect, useCallback, useMemo)
- Implementing lazy loading and code splitting
- Working with Suspense boundaries
- React-specific TypeScript patterns
- Performance optimization with React
Quick Start
Component Structure Template
import { useState, useCallback } from 'react';
interface Props {
userId: string;
onUpdate?: (data: UserData) => void;
}
interface UserData {
name: string;
email: string;
}
function UserProfile({ userId, onUpdate }: Props) {
const [data, setData] = useState<UserData | null>(null);
const handleUpdate = useCallback((newData: UserData) => {
setData(newData);
onUpdate?.(newData);
}, [onUpdate]);
return (
<div>
{/* Component content */}
</div>
);
}
export default UserProfile;
Component Checklist
Creating a React component? Follow this:
- Use function components with typed props (not
React.FC) - Define interfaces for Props and local state
- Use
useCallbackfor event handlers passed to children - Use
useMemofor expensive computations - Lazy load if heavy component:
lazy(() => import()) - Wrap lazy components in
<Suspense>with fallback - Default export at bottom
- No conditional hooks (hooks must be called in same order)
- Pass
refas a prop (noforwardRefneeded in React 19)
Core Hooks Patterns
useState
// Simple state
const [count, setCount] = useState<number>(0);
// Object state
const [user, setUser] = useState<User | null>(null);
// Array state
const [items, setItems] = useState<Item[]>([]);
// Functional updates when depending on previous state
setCount(prev => prev + 1);
setItems(prev => [...prev, newItem]);
useCallback
// Wrap functions passed to child components
const handleClick = useCallback((id: string) => {
console.log('Clicked:', id);
}, []); // Empty deps if no dependencies
// With dependencies
const handleUpdate = useCallback((data: FormData) => {
apiCall(userId, data);
}, [userId]); // Re-create when userId changes
useMemo
// Expensive computation
const sortedItems = useMemo(() => {
return items.sort((a, b) => a.score - b.score);
}, [items]);
// Derived state
const totalPrice = useMemo(() => {
return cart.reduce((sum, item) => sum + item.price, 0);
}, [cart]);
useEffect
// Run once on mount
useEffect(() => {
fetchData();
}, []);
// Run when dependency changes
useEffect(() => {
if (userId) {
loadUserData(userId);
}
}, [userId]);
// Cleanup
useEffect(() => {
const subscription = subscribe(userId);
return () => subscription.unsubscribe();
}, [userId]);
Lazy Loading & Code Splitting
Basic Lazy Loading
import React, { Suspense } from 'react';
// Lazy load heavy component
const HeavyChart = React.lazy(() => import('./HeavyChart'));
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<div>Loading chart...</div>}>
<HeavyChart />
</Suspense>
</div>
);
}
Multiple Lazy Components
const AdminPanel = React.lazy(() => import('./AdminPanel'));
const UserSettings = React.lazy(() => import('./UserSettings'));
const Reports = React.lazy(() => import('./Reports'));
function App() {
return (
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/admin" element={<AdminPanel />} />
<Route path="/settings" element={<UserSettings />} />
<Route path="/reports" element={<Reports />} />
</Routes>
</Suspense>
);
}
Feature-Based Code Splitting
// features/auth/index.tsx
export { default } from './AuthFeature';
// Lazy load entire feature
const AuthFeature = React.lazy(() => import('~/features/auth'));
<Suspense fallback={<FeatureLoader />}>
<AuthFeature />
</Suspense>
Suspense Patterns
Suspense Boundaries
// Wrap data-fetching components
<Suspense fallback={<Skeleton />}>
<UserProfile userId={id} />
</Suspense>
// Nested Suspense for granular loading
<Suspense fallback={<PageLoader />}>
<Header />
<Suspense fallback={<ContentSkeleton />}>
<MainContent />
</Suspense>
<Footer />
</Suspense>
Error Boundaries with Suspense
import { ErrorBoundary } from 'react-error-boundary';
<ErrorBoundary fallback={<ErrorFallback />}>
<Suspense fallback={<Loading />}>
<DataComponent />
</Suspense>
</ErrorBoundary>
TypeScript Patterns
Component Props
// Basic props
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean;
}
// Props with children
interface CardProps {
title: string;
children: React.ReactNode;
}
// Props with specific child types
interface ListProps {
children: React.ReactElement<ItemProps> | React.ReactElement<ItemProps>[];
}
// Props with event handlers
interface FormProps {
onSubmit: (data: FormData) => void;
onChange?: (field: string, value: unknown) => void;
}
Hooks TypeScript
// useState with type
const [user, setUser] = useState<User | null>(null);
const [items, setItems] = useState<Item[]>([]);
// useRef with type
const inputRef = useRef<HTMLInputElement>(null);
const timerRef = useRef<number | null>(null);
// Custom hook with return type
function useUser(id: string): { user: User | null; loading: boolean } {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
// ... implementation
return { user, loading };
}
Performance Optimization
React.memo
// Memoize component to prevent unnecessary re-renders
const UserCard = React.memo<UserCardProps>(({ user, onUpdate }) => {
return (
<div>
<h3>{user.name}</h3>
<button onClick={() => onUpdate(user.id)}>Update</button>
</div>
);
});
// Custom comparison function
const UserCard = React.memo(UserCardComponent, (prevProps, nextProps) => {
return prevProps.user.id === nextProps.user.id;
});
Avoiding Re-renders
// ❌ Bad: Creates new function on every render
function Parent() {
return <Child onClick={() => console.log('clicked')} />;
}
// ✅ Good: Stable function reference
function Parent() {
const handleClick = useCallback(() => {
console.log('clicked');
}, []);
return <Child onClick={handleClick} />;
}
Common Patterns
Conditional Rendering
// Ternary operator
{isLoading ? <Spinner /> : <Content />}
// Logical AND
{error && <ErrorMessage error={error} />}
// Nullish coalescing
{user ?? <GuestView />}
// Early return for loading states
function Component() {
const { data } = useSomeHook();
// ❌ Avoid early returns for loading - breaks hooks rules
// Use Suspense instead
return <div>{data.map(...)}</div>;
}
Lists and Keys
// Always use stable keys
{items.map(item => (
<ItemCard key={item.id} item={item} />
))}
// Never use index as key if list can reorder
// ❌ Bad
{items.map((item, index) => (
<ItemCard key={index} item={item} />
))}
File Organization
Feature-Based Structure
src/
├── features/
│ ├── auth/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── types/
│ │ └── index.tsx
│ └── posts/
│ ├── components/
│ ├── hooks/
│ ├── types/
│ └── index.tsx
├── components/ # Shared components
├── hooks/ # Shared hooks
└── types/ # Shared types
Component Co-location
features/posts/
├── components/
│ ├── PostCard.tsx
│ ├── PostList.tsx
│ └── PostForm.tsx
├── hooks/
│ ├── usePost.ts
│ └── usePosts.ts
├── types/
│ └── post.ts
└── index.tsx # Public API
Common Mistakes to Avoid
1. Conditional Hooks
// ❌ Never do this
function Component({ condition }) {
if (condition) {
const [state, setState] = useState(0); // Breaks rules of hooks
}
}
// ✅ Do this
function Component({ condition }) {
const [state, setState] = useState(0);
// Use state conditionally, not the hook
}
2. Missing Dependencies
// ❌ Bad: Missing dependency
useEffect(() => {
fetchUser(userId);
}, []); // userId should be in deps
// ✅ Good: All dependencies listed
useEffect(() => {
fetchUser(userId);
}, [userId]);
3. Mutating State
// ❌ Bad: Mutating state directly
const handleAdd = () => {
items.push(newItem); // Don't mutate
setItems(items);
};
// ✅ Good: Create new array
const handleAdd = () => {
setItems([...items, newItem]);
};
Additional Resources
For more detailed patterns, see:
- component-patterns.md - Advanced component patterns
- performance.md - Performance optimization techniques
- typescript-patterns.md - TypeScript best practices
- hooks-patterns.md - Custom hooks and advanced patterns
Repository

blencorp
Author
blencorp/claude-code-kit/cli/kits/react/skills/react
38
Stars
5
Forks
Updated1w ago
Added1w ago