react
React best practices and patterns. Use for component design, hooks, state management, and React performance optimization.
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
React Skill
React patterns, hooks, and best practices from Vercel and industry standards.
When to Use This Skill
- Building React components
- Managing state with hooks
- React Query / data fetching
- Performance optimization
- Component composition
📐 Component Patterns
Functional Components
interface UserCardProps {
user: User;
onEdit?: (id: string) => void;
}
export function UserCard({ user, onEdit }: UserCardProps) {
return (
<div className="rounded-lg border p-4">
<h3 className="font-semibold">{user.name}</h3>
<p className="text-gray-600">{user.email}</p>
{onEdit && (
<button onClick={() => onEdit(user.id)}>Edit</button>
)}
</div>
);
}
Compound Components
const Tabs = ({ children, defaultValue }) => {
const [active, setActive] = useState(defaultValue);
return (
<TabsContext.Provider value={{ active, setActive }}>
{children}
</TabsContext.Provider>
);
};
Tabs.List = ({ children }) => (
<div role="tablist" className="flex gap-2">{children}</div>
);
Tabs.Trigger = ({ value, children }) => {
const { active, setActive } = useTabsContext();
return (
<button
role="tab"
aria-selected={active === value}
onClick={() => setActive(value)}
>
{children}
</button>
);
};
// Usage
<Tabs defaultValue="tab1">
<Tabs.List>
<Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
<Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="tab1">Content 1</Tabs.Content>
</Tabs>
🪝 Hooks Best Practices
useState
// Simple state
const [count, setCount] = useState(0);
// Lazy initialization (for expensive computations)
const [data, setData] = useState(() => expensiveComputation());
// Functional updates
setCount(prev => prev + 1);
useEffect
// Fetch data
useEffect(() => {
const controller = new AbortController();
async function fetchData() {
const res = await fetch('/api/data', { signal: controller.signal });
setData(await res.json());
}
fetchData();
return () => controller.abort(); // Cleanup
}, []);
// Event listener with cleanup
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
useMemo & useCallback
// Memoize expensive calculations
const sortedItems = useMemo(() => {
return items.sort((a, b) => a.name.localeCompare(b.name));
}, [items]);
// Memoize callbacks passed to children
const handleClick = useCallback((id: string) => {
setSelected(id);
}, []);
Custom Hooks
function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue] as const;
}
// Usage
const [theme, setTheme] = useLocalStorage('theme', 'light');
📡 Data Fetching (React Query)
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
// Fetch data
function useUsers() {
return useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(res => res.json()),
staleTime: 5 * 60 * 1000, // 5 minutes
});
}
// Mutation with optimistic update
function useUpdateUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (user: User) =>
fetch(`/api/users/${user.id}`, {
method: 'PUT',
body: JSON.stringify(user),
}),
onMutate: async (newUser) => {
await queryClient.cancelQueries(['users', newUser.id]);
const previous = queryClient.getQueryData(['users', newUser.id]);
queryClient.setQueryData(['users', newUser.id], newUser);
return { previous };
},
onError: (err, newUser, context) => {
queryClient.setQueryData(['users', newUser.id], context?.previous);
},
onSettled: () => {
queryClient.invalidateQueries(['users']);
},
});
}
⚡ Performance
React.memo
const ExpensiveList = memo(function ExpensiveList({ items }: { items: Item[] }) {
return (
<ul>
{items.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
);
});
Virtualization
import { FixedSizeList } from 'react-window';
function VirtualList({ items }) {
return (
<FixedSizeList
height={400}
itemCount={items.length}
itemSize={50}
width="100%"
>
{({ index, style }) => (
<div style={style}>{items[index].name}</div>
)}
</FixedSizeList>
);
}
Code Splitting
const Dashboard = lazy(() => import('./pages/Dashboard'));
function App() {
return (
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</Suspense>
);
}
📚 References
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-03-11
- Index updated
- 2026-03-11
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!