with one click
react
Must always be enabled when writing/reviewing React code.
Menu
Must always be enabled when writing/reviewing React code.
Core prompt engineering and context engineering best practices for Claude Code prompts.
TypeScript project initialization best practices
Must always be enabled when writing/reviewing TypeScript code.
Create documentation optimized for ADHD and neurodivergent readers with short scannable content, clear hierarchy, progressive disclosure, actionable steps, and reduced cognitive load. Use when creating or improving any technical documentation (README files, API docs, tutorials, guides, onboarding materials) or when users request accessible, easy-to-scan, or beginner-friendly documentation.
Expert guidance on building production-ready multi-agent AI systems using CrewAI, LangChain, AutoGen, and custom architectures. Use when building agent systems, selecting frameworks, designing multi-agent workflows, debugging agent behavior, or deploying agents to production.
Expert guidance for developing and integrating AI systems using LLM APIs, SDKs, and Model Context Protocol (MCP). Covers API selection, SDK patterns, MCP development, production patterns, security, cost optimization, and architecture decisions for building production-ready AI integrations.
| name | react |
| description | Must always be enabled when writing/reviewing React code. |
<core_principles>
Think harder before adding useEffect. Most scenarios have better alternatives:
<when_not_to_use_effect>
Data transformation for rendering:
// ❌ Bad: Cascading updates
const [filteredItems, setFilteredItems] = useState<Item[]>([]);
useEffect(() => {
setFilteredItems(items.filter(item => item.active));
}, [items]);
// ✅ Good: Direct computation
const filteredItems = items.filter(item => item.active);
Handling user events:
// ❌ Bad: Lost interaction context
useEffect(() => {
if (buttonClicked) {
submitForm();
}
}, [buttonClicked]);
// ✅ Good: Explicit intent
const handleSubmit = () => {
submitForm();
};
Caching expensive computations:
// ❌ Bad: Manual memoization
const [expensiveResult, setExpensiveResult] = useState<Result | null>(null);
useEffect(() => {
setExpensiveResult(computeExpensiveValue(data));
}, [data]);
// ✅ Good: useMemo
const expensiveResult = useMemo(() => computeExpensiveValue(data), [data]);
Resetting state on prop changes:
// ❌ Bad: Manual synchronization
useEffect(() => {
setLocalState(defaultValue);
}, [userId]);
// ✅ Good: Key-based reset
<Profile key={userId} userId={userId} />
</when_not_to_use_effect>
<legitimate_use_cases>
Only use Effects for:
Pattern for data fetching (if not using query client):
useEffect(() => {
let ignore = false;
async function fetchData() {
const result = await api.getData();
if (!ignore) {
setData(result);
}
}
fetchData();
return () => { ignore = true; }; // Cleanup to prevent race conditions
}, [dependency]);
</legitimate_use_cases> </core_principles>
<component_definition>
Always use FC type annotation:
import { FC, PropsWithChildren } from 'react';
// For components without children
type ButtonProps {
label: string;
onClick: () => void;
}
const Button: FC<ButtonProps> = ({ label, onClick }) => {
return <button onClick={onClick}>{label}</button>;
};
// For components that accept children
type CardProps {
title: string;
}
const Card: FC<PropsWithChildren<CardProps>> = ({ title, children }) => {
return (
<div>
<h2>{title}</h2>
<div>{children}</div>
</div>
);
};
Never use function declaration syntax:
// ❌ Bad: Avoid this style
function MyComponent(props: Props) {
return <div />;
}
</component_definition>
<api_requests>
Never use fetch directly in components. Always use the project's query client.
<detection_workflow>
Check project dependencies in package.json:
@apollo/client → Use Apollo Client hooks@tanstack/react-query → Use Tanstack Query hooksswr → Use SWR hooksSearch for existing usage patterns:
useQuery, useMutation, useSWR, useApolloClient in codebaseApply appropriate client:
<apollo_client> Apollo Client (GraphQL):
import { useQuery, useMutation, gql } from '@apollo/client';
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;
const UserProfile: FC<{ userId: string }> = ({ userId }) => {
const { data, loading, error } = useQuery(GET_USER, {
variables: { id: userId },
});
if (loading) return <Spinner />;
if (error) return <ErrorMessage error={error} />;
return <div>{data.user.name}</div>;
};
// Mutations
const UPDATE_USER = gql`
mutation UpdateUser($id: ID!, $name: String!) {
updateUser(id: $id, name: $name) {
id
name
}
}
`;
const EditForm: FC = () => {
const [updateUser, { loading }] = useMutation(UPDATE_USER);
const handleSubmit = async (values: FormValues) => {
await updateUser({ variables: { id: values.id, name: values.name } });
};
return <form onSubmit={handleSubmit}>...</form>;
};
</apollo_client>
<tanstack_query> Tanstack Query (REST):
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
const UserProfile: FC<{ userId: string }> = ({ userId }) => {
const { data, isLoading, error } = useQuery({
queryKey: ['user', userId],
queryFn: () => api.getUser(userId),
});
if (isLoading) return <Spinner />;
if (error) return <ErrorMessage error={error} />;
return <div>{data.name}</div>;
};
// Mutations with cache invalidation
const EditForm: FC = () => {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (values: FormValues) => api.updateUser(values),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['user'] });
},
});
const handleSubmit = (values: FormValues) => {
mutation.mutate(values);
};
return <form onSubmit={handleSubmit}>...</form>;
};
</tanstack_query>
**SWR**: ```tsx import useSWR from 'swr'; import useSWRMutation from 'swr/mutation';const UserProfile: FC<{ userId: string }> = ({ userId }) => {
const { data, error, isLoading } = useSWR(
/api/users/${userId},
fetcher
);
if (isLoading) return ; if (error) return ;
return
// Mutations const EditForm: FC = () => { const { trigger, isMutating } = useSWRMutation( '/api/users', updateUser );
const handleSubmit = async (values: FormValues) => { await trigger(values); };
return
...; };</swr>
</detection_workflow>
**Benefits of query clients**:
- Automatic caching and deduplication
- Loading/error state management
- Race condition handling
- Cache invalidation and refetching
- Optimistic updates support
</api_requests>
</core_principles>
<workflow>
## Implementation Workflow
1. **Before writing component**:
- Identify data dependencies and state requirements
- Think harder: Can state be derived instead of stored?
- Plan event handlers before considering Effects
2. **During implementation**:
- Define component with FC type annotation
- Calculate derived values at top level
- Use useMemo only for expensive computations
- Handle user interactions in event handlers
- Use query client hooks for API requests
3. **Effect review checklist**:
- [ ] Is this synchronizing with an external system?
- [ ] Could this be a calculated value instead?
- [ ] Should this be in an event handler?
- [ ] Am I using the right hook (useMemo, key prop)?
- [ ] If data fetching, is query client available?
4. **If Effect is necessary**:
- Document why Effect is required
- Implement proper cleanup to prevent memory leaks
- Handle race conditions for async operations
</workflow>
<anti_patterns>
## Anti-Patterns to Avoid
❌ **Chaining Effects**:
```tsx
// Bad: Effects triggering each other
useEffect(() => setB(a), [a]);
useEffect(() => setC(b), [b]);
// Good: Direct computation or single event handler
const b = computeB(a);
const c = computeC(b);
❌ Effect-based initialization:
// Bad: One-time initialization in Effect
useEffect(() => {
setData(expensiveInit());
}, []);
// Good: useState with initializer
const [data] = useState(() => expensiveInit());
❌ Direct fetch calls:
// Bad: Manual fetch in component
useEffect(() => {
fetch('/api/data').then(res => res.json()).then(setData);
}, []);
// Good: Use query client
const { data } = useQuery({ queryKey: ['data'], queryFn: fetchData });
</anti_patterns>