Install
$ agentstack add skill-chandrudp29-skillhub-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.
About
React Patterns
Modern React (18+) patterns for production. TypeScript assumed.
When to Use
- Building new React components or pages
- Reviewing React code for quality or performance
- Debugging re-renders or stale state
- Deciding where to put state
Component Design
Small, focused, composable:
// Bad — one component doing too much
function UserDashboard({ userId }: { userId: string }) {
const [user, setUser] = useState(null);
const [orders, setOrders] = useState([]);
const [notifications, setNotifications] = useState([]);
// 300 lines of JSX mixing user info, orders table, notification bell...
}
// Good — composed from focused pieces
function UserDashboard({ userId }: { userId: string }) {
return (
);
}
Hooks Patterns
Data Fetching
// Custom hook — logic separate from UI
function useUser(userId: string) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let cancelled = false; // prevent state update after unmount
setLoading(true);
fetchUser(userId)
.then(data => { if (!cancelled) setUser(data); })
.catch(err => { if (!cancelled) setError(err); })
.finally(() => { if (!cancelled) setLoading(false); });
return () => { cancelled = true; };
}, [userId]);
return { user, loading, error };
}
// Use it in the component — clean separation
function UserProfile({ userId }: { userId: string }) {
const { user, loading, error } = useUser(userId);
if (loading) return ;
if (error) return ;
if (!user) return null;
return {user.name};
}
Use React Query / TanStack Query instead of manual useEffect for data fetching in real apps:
import { useQuery } from "@tanstack/react-query";
function UserProfile({ userId }: { userId: string }) {
const { data: user, isLoading, error } = useQuery({
queryKey: ["user", userId],
queryFn: () => fetchUser(userId),
staleTime: 5 * 60 * 1000, // 5 minutes
});
// handles caching, deduplication, background refresh automatically
}
State Management
Where to put state:
| State type | Where | |---|---| | UI state (open/closed, selected tab) | useState in the component | | Shared UI state (theme, sidebar) | React Context | | Server state (user data, API responses) | React Query / SWR | | Complex client state | Zustand / Jotai |
// Context for shared UI state — not for server data
const ThemeContext = createContext void } | null>(null);
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState("light");
const toggle = useCallback(() => setTheme(t => t === "light" ? "dark" : "light"), []);
return {children};
}
export function useTheme() {
const ctx = useContext(ThemeContext);
if (!ctx) throw new Error("useTheme must be inside ThemeProvider");
return ctx;
}
Performance
useCallback and useMemo — only when there's a measurable problem:
// Use useMemo for expensive computations
const sortedItems = useMemo(
() => items.sort((a, b) => b.score - a.score),
[items] // recalculate only when items changes
);
// Use useCallback for functions passed to memoized children
const handleSelect = useCallback((id: string) => {
setSelectedIds(prev => [...prev, id]);
}, []); // stable reference — won't trigger child re-renders
Don't add useMemo/useCallback everywhere "just in case". Profile first with React DevTools.
Avoid re-renders:
// BAD — new object created on every render
// GOOD — stable reference
const style = { color: "red" } as const;
// Or with useMemo if it depends on props/state
const style = useMemo(() => ({ color: isError ? "red" : "green" }), [isError]);
List rendering:
// Always key by stable, unique ID — never array index for dynamic lists
{items.map(item => (
// id, not index
))}
TypeScript Patterns
// Props: explicit interface, not inline type
interface ButtonProps {
label: string;
onClick: () => void;
variant?: "primary" | "secondary" | "danger";
disabled?: boolean;
}
// Component return type
function Button({ label, onClick, variant = "primary", disabled = false }: ButtonProps): JSX.Element {
return (
{label}
);
}
// Event handlers
const handleChange = (e: React.ChangeEvent) => {
setValue(e.target.value);
};
// Ref typing
const inputRef = useRef(null);
Common Mistakes
| Mistake | Fix | |---|---| | useEffect with missing deps | Add missing deps or use useCallback to stabilize functions | | State update after unmount | Add cleanup in useEffect with cancelled flag or AbortController | | Index as list key | Use stable unique IDs | | Fetching in useEffect directly | Use React Query or similar | | Context for server data | Use React Query — Context causes full subtree re-renders |
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: chandrudp29
- Source: chandrudp29/skillhub
- License: MIT
- Homepage: https://pypi.org/project/skillhub-ai/
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.