React Component Skill
Description
Generate React components with TypeScript, hooks, and accessibility best practices.
Trigger
-
/react command
-
User requests React component
-
User needs React hooks
Prompt
You are a React expert that creates modern, accessible components.
Functional Component with Props
import { FC, memo } from 'react';
interface ButtonProps { variant?: 'primary' | 'secondary' | 'danger'; size?: 'sm' | 'md' | 'lg'; disabled?: boolean; loading?: boolean; onClick?: () => void; children: React.ReactNode; }
export const Button: FC<ButtonProps> = memo(({ variant = 'primary', size = 'md', disabled = false, loading = false, onClick, children, }) => { const baseStyles = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors';
const variants = { primary: 'bg-blue-600 text-white hover:bg-blue-700 disabled:bg-blue-300', secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300 disabled:bg-gray-100', danger: 'bg-red-600 text-white hover:bg-red-700 disabled:bg-red-300', };
const sizes = { sm: 'px-3 py-1.5 text-sm', md: 'px-4 py-2 text-base', lg: 'px-6 py-3 text-lg', };
return (
<button
type="button"
className={${baseStyles} ${variants[variant]} ${sizes[size]}}
disabled={disabled || loading}
onClick={onClick}
aria-busy={loading}
>
{loading && (
<svg className="animate-spin -ml-1 mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg>
)}
{children}
</button>
);
});
Button.displayName = 'Button';
Custom Hook
import { useState, useEffect, useCallback } from 'react';
interface UseFetchResult<T> { data: T | null; loading: boolean; error: Error | null; refetch: () => void; }
export function useFetch<T>(url: string): UseFetchResult<T> { const [data, setData] = useState<T | null>(null); const [loading, setLoading] = useState(true); const [error, setError] = useState<Error | null>(null);
const fetchData = useCallback(async () => { setLoading(true); setError(null);
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const json = await response.json();
setData(json);
} catch (e) {
setError(e instanceof Error ? e : new Error('Unknown error'));
} finally {
setLoading(false);
}
}, [url]);
useEffect(() => { fetchData(); }, [fetchData]);
return { data, loading, error, refetch: fetchData }; }
Context Provider
import { createContext, useContext, useState, ReactNode } from 'react';
interface User { id: string; name: string; email: string; }
interface AuthContextType { user: User | null; login: (email: string, password: string) => Promise<void>; logout: () => void; isAuthenticated: boolean; }
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function AuthProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState<User | null>(null);
const login = async (email: string, password: string) => { const response = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }), }); const data = await response.json(); setUser(data.user); };
const logout = () => setUser(null);
return ( <AuthContext.Provider value={{ user, login, logout, isAuthenticated: !!user }}> {children} </AuthContext.Provider> ); }
export function useAuth() { const context = useContext(AuthContext); if (!context) throw new Error('useAuth must be used within AuthProvider'); return context; }
Tags
react , typescript , components , hooks , frontend
Compatibility
-
Codex: ✅
-
Claude Code: ✅