Install
$ agentstack add skill-benshapyro-cadre-devkit-claude-react-patterns ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
React Patterns Skill
Modern React patterns for TypeScript applications.
Component Structure
File Organization
components/
├── ui/ # Reusable primitives (Button, Input, Card)
├── features/ # Feature-specific components
│ └── auth/
│ ├── LoginForm.tsx
│ └── SignupForm.tsx
├── layouts/ # Page layouts
└── providers/ # Context providers
Component Template
interface ComponentNameProps {
// Required props first
title: string;
onAction: () => void;
// Optional props with defaults
variant?: 'primary' | 'secondary';
disabled?: boolean;
children?: React.ReactNode;
}
export function ComponentName({
title,
onAction,
variant = 'primary',
disabled = false,
children,
}: ComponentNameProps) {
return (/* JSX */);
}
Hooks Best Practices
useState
// Prefer explicit types for complex state
const [user, setUser] = useState(null);
// Use functional updates when depending on previous state
setCount(prev => prev + 1);
// Group related state or use useReducer for complex state
const [form, setForm] = useState({ name: '', email: '' });
useEffect
// Always specify dependencies explicitly
useEffect(() => {
fetchData();
}, [userId]); // Only re-run when userId changes
// Cleanup subscriptions
useEffect(() => {
const subscription = subscribe();
return () => subscription.unsubscribe();
}, []);
// Avoid objects/arrays in deps - extract primitives
const { id } = user;
useEffect(() => { /* ... */ }, [id]); // Not [user]
useMemo / useCallback
// Memoize expensive calculations
const sortedItems = useMemo(
() => items.sort((a, b) => a.name.localeCompare(b.name)),
[items]
);
// Memoize callbacks passed to children
const handleClick = useCallback(() => {
onAction(id);
}, [onAction, id]);
Custom Hooks
// Extract reusable logic into custom hooks
function useDebounce(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
// Prefix with "use", return typed values
function useAuth() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
// ... logic
return { user, loading, signIn, signOut } as const;
}
State Management
Context + useReducer (Complex Local State)
// Define action types and state
type State = { count: number; loading: boolean };
type Action =
| { type: 'increment' }
| { type: 'decrement' }
| { type: 'setLoading'; payload: boolean };
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'increment': return { ...state, count: state.count + 1 };
case 'decrement': return { ...state, count: state.count - 1 };
case 'setLoading': return { ...state, loading: action.payload };
}
}
// Context provider
const CounterContext = createContext;
} | null>(null);
function CounterProvider({ children }: { children: React.ReactNode }) {
const [state, dispatch] = useReducer(reducer, { count: 0, loading: false });
return (
{children}
);
}
// Custom hook for consuming
function useCounter() {
const context = useContext(CounterContext);
if (!context) throw new Error('useCounter must be used within CounterProvider');
return context;
}
Server State (React Query / TanStack Query)
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
// Fetching data
function useUsers() {
return useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(res => res.json()),
staleTime: 5 * 60 * 1000, // 5 minutes
});
}
// Mutations with optimistic updates
function useUpdateUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (user: User) =>
fetch(`/api/users/${user.id}`, {
method: 'PUT',
body: JSON.stringify(user),
}),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] });
},
});
}
// Usage
function UserList() {
const { data: users, isLoading, error } = useUsers();
const updateUser = useUpdateUser();
if (isLoading) return ;
if (error) return ;
return (/* render users */);
}
When to Use What
| Scenario | Solution | |----------|----------| | Simple component state | useState | | Complex state with many actions | useReducer | | State shared across components | Context + useReducer | | Server data (fetch, cache, sync) | React Query / SWR | | Global app state (auth, theme) | Context or Zustand |
Component Patterns
Composition over Props
// Prefer composition
Title
Content
// Over prop drilling
Render Props / Children as Function
interface DataFetcherProps {
url: string;
children: (data: T, loading: boolean) => React.ReactNode;
}
function DataFetcher({ url, children }: DataFetcherProps) {
const { data, loading } = useFetch(url);
return <>{children(data, loading)};
}
Controlled vs Uncontrolled
// Controlled - parent owns state
// Uncontrolled - component owns state, use ref to access
Error Handling
Error Boundaries
class ErrorBoundary extends Component {
state = { hasError: false, error: null };
static getDerivedStateFromError(error: Error) {
return { hasError: true, error };
}
componentDidCatch(error: Error, info: ErrorInfo) {
console.error('Error caught:', error, info);
}
render() {
if (this.state.hasError) {
return this.props.fallback ?? Something went wrong;
}
return this.props.children;
}
}
Async Error Handling
const [error, setError] = useState(null);
async function handleSubmit() {
try {
setError(null);
await submitForm(data);
} catch (e) {
setError(e instanceof Error ? e : new Error('Unknown error'));
}
}
Performance
Avoid Unnecessary Renders
- Use
React.memo()for pure components receiving complex props - Split context providers to minimize re-renders
- Use
useMemofor expensive derived state - Lazy load heavy components with
React.lazy()
Code Splitting
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
}>
);
}
TypeScript Integration
Event Handlers
function handleChange(e: React.ChangeEvent) { }
function handleSubmit(e: React.FormEvent) { }
function handleClick(e: React.MouseEvent) { }
Generic Components
interface ListProps {
items: T[];
renderItem: (item: T) => React.ReactNode;
keyExtractor: (item: T) => string;
}
function List({ items, renderItem, keyExtractor }: ListProps) {
return (
{items.map(item => (
{renderItem(item)}
))}
);
}
Anti-Patterns
- Don't mutate state directly
- Don't call hooks conditionally or in loops
- Don't use array index as key for dynamic lists
- Don't fetch data in useEffect without cleanup/cancellation
- Don't ignore dependency array warnings
- Don't overuse context for frequently-changing values
Version
- v1.0.0 (2025-12-05): Added YAML frontmatter, initial documented version
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: benshapyro
- Source: benshapyro/cadre-devkit-claude
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.