$npx -y skills add affaan-m/ECC --skill frontend-patternsFrontend development patterns for React, Next.js, state management, performance optimization, and UI best practices.
| 1 | # Frontend Development Patterns |
| 2 | |
| 3 | Modern frontend patterns for React, Next.js, and performant user interfaces. |
| 4 | |
| 5 | ## When to Activate |
| 6 | |
| 7 | - Building React components (composition, props, rendering) |
| 8 | - Managing state (useState, useReducer, Zustand, Context) |
| 9 | - Implementing data fetching (SWR, React Query, server components) |
| 10 | - Optimizing performance (memoization, virtualization, code splitting) |
| 11 | - Working with forms (validation, controlled inputs, Zod schemas) |
| 12 | - Handling client-side routing and navigation |
| 13 | - Building accessible, responsive UI patterns |
| 14 | |
| 15 | ## Privacy and Data Boundaries |
| 16 | |
| 17 | Frontend examples should use synthetic or domain-generic data. Do not collect, log, persist, or display credentials, access tokens, SSNs, health data, payment details, private emails, phone numbers, or other sensitive personal data unless the user explicitly requests a scoped implementation with appropriate validation, redaction, and access controls. |
| 18 | |
| 19 | Avoid adding analytics, tracking pixels, third-party scripts, or external data sinks without explicit approval. When handling user data, prefer least-privilege APIs, client-side redaction before logging, and server-side validation for every boundary. |
| 20 | |
| 21 | ## Component Patterns |
| 22 | |
| 23 | ### Composition Over Inheritance |
| 24 | |
| 25 | ```typescript |
| 26 | // PASS: GOOD: Component composition |
| 27 | interface CardProps { |
| 28 | children: React.ReactNode |
| 29 | variant?: 'default' | 'outlined' |
| 30 | } |
| 31 | |
| 32 | export function Card({ children, variant = 'default' }: CardProps) { |
| 33 | return <div className={`card card-${variant}`}>{children}</div> |
| 34 | } |
| 35 | |
| 36 | export function CardHeader({ children }: { children: React.ReactNode }) { |
| 37 | return <div className="card-header">{children}</div> |
| 38 | } |
| 39 | |
| 40 | export function CardBody({ children }: { children: React.ReactNode }) { |
| 41 | return <div className="card-body">{children}</div> |
| 42 | } |
| 43 | |
| 44 | // Usage |
| 45 | <Card> |
| 46 | <CardHeader>Title</CardHeader> |
| 47 | <CardBody>Content</CardBody> |
| 48 | </Card> |
| 49 | ``` |
| 50 | |
| 51 | ### Compound Components |
| 52 | |
| 53 | ```typescript |
| 54 | interface TabsContextValue { |
| 55 | activeTab: string |
| 56 | setActiveTab: (tab: string) => void |
| 57 | } |
| 58 | |
| 59 | const TabsContext = createContext<TabsContextValue | undefined>(undefined) |
| 60 | |
| 61 | export function Tabs({ children, defaultTab }: { |
| 62 | children: React.ReactNode |
| 63 | defaultTab: string |
| 64 | }) { |
| 65 | const [activeTab, setActiveTab] = useState(defaultTab) |
| 66 | |
| 67 | return ( |
| 68 | <TabsContext.Provider value={{ activeTab, setActiveTab }}> |
| 69 | {children} |
| 70 | </TabsContext.Provider> |
| 71 | ) |
| 72 | } |
| 73 | |
| 74 | export function TabList({ children }: { children: React.ReactNode }) { |
| 75 | return <div className="tab-list">{children}</div> |
| 76 | } |
| 77 | |
| 78 | export function Tab({ id, children }: { id: string, children: React.ReactNode }) { |
| 79 | const context = useContext(TabsContext) |
| 80 | if (!context) throw new Error('Tab must be used within Tabs') |
| 81 | |
| 82 | return ( |
| 83 | <button |
| 84 | className={context.activeTab === id ? 'active' : ''} |
| 85 | onClick={() => context.setActiveTab(id)} |
| 86 | > |
| 87 | {children} |
| 88 | </button> |
| 89 | ) |
| 90 | } |
| 91 | |
| 92 | // Usage |
| 93 | <Tabs defaultTab="overview"> |
| 94 | <TabList> |
| 95 | <Tab id="overview">Overview</Tab> |
| 96 | <Tab id="details">Details</Tab> |
| 97 | </TabList> |
| 98 | </Tabs> |
| 99 | ``` |
| 100 | |
| 101 | ### Render Props Pattern |
| 102 | |
| 103 | ```typescript |
| 104 | interface DataLoaderProps<T> { |
| 105 | url: string |
| 106 | children: (data: T | null, loading: boolean, error: Error | null) => React.ReactNode |
| 107 | } |
| 108 | |
| 109 | export function DataLoader<T>({ url, children }: DataLoaderProps<T>) { |
| 110 | const [data, setData] = useState<T | null>(null) |
| 111 | const [loading, setLoading] = useState(true) |
| 112 | const [error, setError] = useState<Error | null>(null) |
| 113 | |
| 114 | useEffect(() => { |
| 115 | fetch(url) |
| 116 | .then(res => res.json()) |
| 117 | .then(setData) |
| 118 | .catch(setError) |
| 119 | .finally(() => setLoading(false)) |
| 120 | }, [url]) |
| 121 | |
| 122 | return <>{children(data, loading, error)}</> |
| 123 | } |
| 124 | |
| 125 | // Usage |
| 126 | <DataLoader<Market[]> url="/api/markets"> |
| 127 | {(markets, loading, error) => { |
| 128 | if (loading) return <Spinner /> |
| 129 | if (error) return <Error error={error} /> |
| 130 | return <MarketList markets={markets!} /> |
| 131 | }} |
| 132 | </DataLoader> |
| 133 | ``` |
| 134 | |
| 135 | ## Custom Hooks Patterns |
| 136 | |
| 137 | ### State Management Hook |
| 138 | |
| 139 | ```typescript |
| 140 | export function useToggle(initialValue = false): [boolean, () => void] { |
| 141 | const [value, setValue] = useState(initialValue) |
| 142 | |
| 143 | const toggle = useCallback(() => { |
| 144 | setValue(v => !v) |
| 145 | }, []) |
| 146 | |
| 147 | return [value, toggle] |
| 148 | } |
| 149 | |
| 150 | // Usage |
| 151 | const [isOpen, toggleOpen] = useToggle() |
| 152 | ``` |
| 153 | |
| 154 | ### Async Data Fetching Hook |
| 155 | |
| 156 | ```typescript |
| 157 | interface UseQueryOptions<T> { |
| 158 | onSuccess?: (data: T) => void |
| 159 | onError?: (error: Error) => void |
| 160 | enabled?: boolean |
| 161 | } |
| 162 | |
| 163 | export function useQuery<T>( |
| 164 | key: string, |
| 165 | fetcher: () => Promise<T>, |
| 166 | options?: UseQueryOptions<T> |
| 167 | ) { |
| 168 | const [data, setData] = useState<T | null>(null) |
| 169 | const [error, setError] = useState<Error | null>(null) |
| 170 | const [loading, setLoading] = useState(false) |
| 171 | |
| 172 | // Keep the latest fetcher/options in refs so refetch stays referentially |
| 173 | // stable even when callers pass inline functions and object literals. |
| 174 | // Without this, every render creates a new refetch, and t |