Modern React patterns for TypeScript applications including hooks, state management, and component composition. Use when building React components, managing state, or implementing React best practices.
Provides modern React patterns and TypeScript best practices for building scalable applications. Claude uses this when creating React components, implementing hooks, or managing state to ensure idiomatic, performant code.
/plugin marketplace add benshapyro/cadre-devkit-claude/plugin install benshapyro-cadre-devkit-claude@benshapyro/cadre-devkit-claudeThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Modern React patterns for TypeScript applications.
components/
├── ui/ # Reusable primitives (Button, Input, Card)
├── features/ # Feature-specific components
│ └── auth/
│ ├── LoginForm.tsx
│ └── SignupForm.tsx
├── layouts/ # Page layouts
└── providers/ # Context providers
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 */);
}
// Prefer explicit types for complex state
const [user, setUser] = useState<User | null>(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: '' });
// 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]
// 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]);
// Extract reusable logic into custom hooks
function useDebounce<T>(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<User | null>(null);
const [loading, setLoading] = useState(true);
// ... logic
return { user, loading, signIn, signOut } as const;
}
// 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<{
state: State;
dispatch: React.Dispatch<Action>;
} | null>(null);
function CounterProvider({ children }: { children: React.ReactNode }) {
const [state, dispatch] = useReducer(reducer, { count: 0, loading: false });
return (
<CounterContext.Provider value={{ state, dispatch }}>
{children}
</CounterContext.Provider>
);
}
// Custom hook for consuming
function useCounter() {
const context = useContext(CounterContext);
if (!context) throw new Error('useCounter must be used within CounterProvider');
return context;
}
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 <Spinner />;
if (error) return <Error message={error.message} />;
return (/* render users */);
}
| 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 |
// Prefer composition
<Card>
<Card.Header>Title</Card.Header>
<Card.Body>Content</Card.Body>
</Card>
// Over prop drilling
<Card header="Title" body="Content" />
interface DataFetcherProps<T> {
url: string;
children: (data: T, loading: boolean) => React.ReactNode;
}
function DataFetcher<T>({ url, children }: DataFetcherProps<T>) {
const { data, loading } = useFetch<T>(url);
return <>{children(data, loading)}</>;
}
// Controlled - parent owns state
<Input value={value} onChange={setValue} />
// Uncontrolled - component owns state, use ref to access
<Input defaultValue="initial" ref={inputRef} />
class ErrorBoundary extends Component<Props, State> {
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 ?? <div>Something went wrong</div>;
}
return this.props.children;
}
}
const [error, setError] = useState<Error | null>(null);
async function handleSubmit() {
try {
setError(null);
await submitForm(data);
} catch (e) {
setError(e instanceof Error ? e : new Error('Unknown error'));
}
}
React.memo() for pure components receiving complex propsuseMemo for expensive derived stateReact.lazy()const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<Loading />}>
<HeavyComponent />
</Suspense>
);
}
function handleChange(e: React.ChangeEvent<HTMLInputElement>) { }
function handleSubmit(e: React.FormEvent<HTMLFormElement>) { }
function handleClick(e: React.MouseEvent<HTMLButtonElement>) { }
interface ListProps<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
keyExtractor: (item: T) => string;
}
function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
return (
<ul>
{items.map(item => (
<li key={keyExtractor(item)}>{renderItem(item)}</li>
))}
</ul>
);
}
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.