[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6DXF2F5GFN9DNRP2EBEKFPQ":3,"skill-same:01M6DXF2F5GFN9DNRP2EBEKFPQ":70},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":41,"linkOnly":42,"markdownContent":43,"markdownBody":44,"frontMatter":45,"refName":48,"commitSha":49,"skillDirectory":50,"forksCount":14,"repositoryHtmlUrl":51,"repositoryHomepageUrl":6,"ownerHtmlUrl":52,"ownerBlogUrl":53,"ownerDescription":54,"updatedAt":55,"install":56,"resources":69},"01M6DXF2F5GFN9DNRP2EBEKFPQ","frontend-patterns",null,"Frontend development patterns for React, Next.js, state management, performance optimization, and UI best practices.","EthanSheehan\u002FGrid-Sentinel","EthanSheehan","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F174215275?v=4","01M6DX9589ENESB2AYW9YK4Y50","Ethan Sheehan","01M6DX95P06JXASASFQZRFQ1NM",0,"MIT","https:\u002F\u002Fgithub.com\u002FEthanSheehan\u002FGrid-Sentinel\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fcc-skill-frontend-patterns\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"patterns","frontend patterns","frontend","Optimization","next","frontend development","management","performance optimization","js","Next.js","ui","state","best practices","state management","development","react","performance","2026-11-10 10:12:30",false,"---\nname: frontend-patterns\ndescription: Frontend development patterns for React, Next.js, state management, performance optimization, and UI best practices.\nauthor: affaan-m\nversion: \"1.0\"\n---\n\n# Frontend Development Patterns\n\nModern frontend patterns for React, Next.js, and performant user interfaces.\n\n## Component Patterns\n\n### Composition Over Inheritance\n\n```typescript\n\u002F\u002F ✅ GOOD: Component composition\ninterface CardProps {\n  children: React.ReactNode\n  variant?: 'default' | 'outlined'\n}\n\nexport function Card({ children, variant = 'default' }: CardProps) {\n  return \u003Cdiv className={`card card-${variant}`}>{children}\u003C\u002Fdiv>\n}\n\nexport function CardHeader({ children }: { children: React.ReactNode }) {\n  return \u003Cdiv className=\"card-header\">{children}\u003C\u002Fdiv>\n}\n\nexport function CardBody({ children }: { children: React.ReactNode }) {\n  return \u003Cdiv className=\"card-body\">{children}\u003C\u002Fdiv>\n}\n\n\u002F\u002F Usage\n\u003CCard>\n  \u003CCardHeader>Title\u003C\u002FCardHeader>\n  \u003CCardBody>Content\u003C\u002FCardBody>\n\u003C\u002FCard>\n```\n\n### Compound Components\n\n```typescript\ninterface TabsContextValue {\n  activeTab: string\n  setActiveTab: (tab: string) => void\n}\n\nconst TabsContext = createContext\u003CTabsContextValue | undefined>(undefined)\n\nexport function Tabs({ children, defaultTab }: {\n  children: React.ReactNode\n  defaultTab: string\n}) {\n  const [activeTab, setActiveTab] = useState(defaultTab)\n\n  return (\n    \u003CTabsContext.Provider value={{ activeTab, setActiveTab }}>\n      {children}\n    \u003C\u002FTabsContext.Provider>\n  )\n}\n\nexport function TabList({ children }: { children: React.ReactNode }) {\n  return \u003Cdiv className=\"tab-list\">{children}\u003C\u002Fdiv>\n}\n\nexport function Tab({ id, children }: { id: string, children: React.ReactNode }) {\n  const context = useContext(TabsContext)\n  if (!context) throw new Error('Tab must be used within Tabs')\n\n  return (\n    \u003Cbutton\n      className={context.activeTab === id ? 'active' : ''}\n      onClick={() => context.setActiveTab(id)}\n    >\n      {children}\n    \u003C\u002Fbutton>\n  )\n}\n\n\u002F\u002F Usage\n\u003CTabs defaultTab=\"overview\">\n  \u003CTabList>\n    \u003CTab id=\"overview\">Overview\u003C\u002FTab>\n    \u003CTab id=\"details\">Details\u003C\u002FTab>\n  \u003C\u002FTabList>\n\u003C\u002FTabs>\n```\n\n### Render Props Pattern\n\n```typescript\ninterface DataLoaderProps\u003CT> {\n  url: string\n  children: (data: T | null, loading: boolean, error: Error | null) => React.ReactNode\n}\n\nexport function DataLoader\u003CT>({ url, children }: DataLoaderProps\u003CT>) {\n  const [data, setData] = useState\u003CT | null>(null)\n  const [loading, setLoading] = useState(true)\n  const [error, setError] = useState\u003CError | null>(null)\n\n  useEffect(() => {\n    fetch(url)\n      .then(res => res.json())\n      .then(setData)\n      .catch(setError)\n      .finally(() => setLoading(false))\n  }, [url])\n\n  return \u003C>{children(data, loading, error)}\u003C\u002F>\n}\n\n\u002F\u002F Usage\n\u003CDataLoader\u003CMarket[]> url=\"\u002Fapi\u002Fmarkets\">\n  {(markets, loading, error) => {\n    if (loading) return \u003CSpinner \u002F>\n    if (error) return \u003CError error={error} \u002F>\n    return \u003CMarketList markets={markets!} \u002F>\n  }}\n\u003C\u002FDataLoader>\n```\n\n## Custom Hooks Patterns\n\n### State Management Hook\n\n```typescript\nexport function useToggle(initialValue = false): [boolean, () => void] {\n  const [value, setValue] = useState(initialValue)\n\n  const toggle = useCallback(() => {\n    setValue(v => !v)\n  }, [])\n\n  return [value, toggle]\n}\n\n\u002F\u002F Usage\nconst [isOpen, toggleOpen] = useToggle()\n```\n\n### Async Data Fetching Hook\n\n```typescript\ninterface UseQueryOptions\u003CT> {\n  onSuccess?: (data: T) => void\n  onError?: (error: Error) => void\n  enabled?: boolean\n}\n\nexport function useQuery\u003CT>(\n  key: string,\n  fetcher: () => Promise\u003CT>,\n  options?: UseQueryOptions\u003CT>\n) {\n  const [data, setData] = useState\u003CT | null>(null)\n  const [error, setError] = useState\u003CError | null>(null)\n  const [loading, setLoading] = useState(false)\n\n  const refetch = useCallback(async () => {\n    setLoading(true)\n    setError(null)\n\n    try {\n      const result = await fetcher()\n      setData(result)\n      options?.onSuccess?.(result)\n    } catch (err) {\n      const error = err as Error\n      setError(error)\n      options?.onError?.(error)\n    } finally {\n      setLoading(false)\n    }\n  }, [fetcher, options])\n\n  useEffect(() => {\n    if (options?.enabled !== false) {\n      refetch()\n    }\n  }, [key, refetch, options?.enabled])\n\n  return { data, error, loading, refetch }\n}\n\n\u002F\u002F Usage\nconst { data: markets, loading, error, refetch } = useQuery(\n  'markets',\n  () => fetch('\u002Fapi\u002Fmarkets').then(r => r.json()),\n  {\n    onSuccess: data => console.log('Fetched', data.length, 'markets'),\n    onError: err => console.error('Failed:', err)\n  }\n)\n```\n\n### Debounce Hook\n\n```typescript\nexport function useDebounce\u003CT>(value: T, delay: number): T {\n  const [debouncedValue, setDebouncedValue] = useState\u003CT>(value)\n\n  useEffect(() => {\n    const handler = setTimeout(() => {\n      setDebouncedValue(value)\n    }, delay)\n\n    return () => clearTimeout(handler)\n  }, [value, delay])\n\n  return debouncedValue\n}\n\n\u002F\u002F Usage\nconst [searchQuery, setSearchQuery] = useState('')\nconst debouncedQuery = useDebounce(searchQuery, 500)\n\nuseEffect(() => {\n  if (debouncedQuery) {\n    performSearch(debouncedQuery)\n  }\n}, [debouncedQuery])\n```\n\n## State Management Patterns\n\n### Context + Reducer Pattern\n\n```typescript\ninterface State {\n  markets: Market[]\n  selectedMarket: Market | null\n  loading: boolean\n}\n\ntype Action =\n  | { type: 'SET_MARKETS'; payload: Market[] }\n  | { type: 'SELECT_MARKET'; payload: Market }\n  | { type: 'SET_LOADING'; payload: boolean }\n\nfunction reducer(state: State, action: Action): State {\n  switch (action.type) {\n    case 'SET_MARKETS':\n      return { ...state, markets: action.payload }\n    case 'SELECT_MARKET':\n      return { ...state, selectedMarket: action.payload }\n    case 'SET_LOADING':\n      return { ...state, loading: action.payload }\n    default:\n      return state\n  }\n}\n\nconst MarketContext = createContext\u003C{\n  state: State\n  dispatch: Dispatch\u003CAction>\n} | undefined>(undefined)\n\nexport function MarketProvider({ children }: { children: React.ReactNode }) {\n  const [state, dispatch] = useReducer(reducer, {\n    markets: [],\n    selectedMarket: null,\n    loading: false\n  })\n\n  return (\n    \u003CMarketContext.Provider value={{ state, dispatch }}>\n      {children}\n    \u003C\u002FMarketContext.Provider>\n  )\n}\n\nexport function useMarkets() {\n  const context = useContext(MarketContext)\n  if (!context) throw new Error('useMarkets must be used within MarketProvider')\n  return context\n}\n```\n\n## Performance Optimization\n\n### Memoization\n\n```typescript\n\u002F\u002F ✅ useMemo for expensive computations\nconst sortedMarkets = useMemo(() => {\n  return markets.sort((a, b) => b.volume - a.volume)\n}, [markets])\n\n\u002F\u002F ✅ useCallback for functions passed to children\nconst handleSearch = useCallback((query: string) => {\n  setSearchQuery(query)\n}, [])\n\n\u002F\u002F ✅ React.memo for pure components\nexport const MarketCard = React.memo\u003CMarketCardProps>(({ market }) => {\n  return (\n    \u003Cdiv className=\"market-card\">\n      \u003Ch3>{market.name}\u003C\u002Fh3>\n      \u003Cp>{market.description}\u003C\u002Fp>\n    \u003C\u002Fdiv>\n  )\n})\n```\n\n### Code Splitting & Lazy Loading\n\n```typescript\nimport { lazy, Suspense } from 'react'\n\n\u002F\u002F ✅ Lazy load heavy components\nconst HeavyChart = lazy(() => import('.\u002FHeavyChart'))\nconst ThreeJsBackground = lazy(() => import('.\u002FThreeJsBackground'))\n\nexport function Dashboard() {\n  return (\n    \u003Cdiv>\n      \u003CSuspense fallback={\u003CChartSkeleton \u002F>}>\n        \u003CHeavyChart data={data} \u002F>\n      \u003C\u002FSuspense>\n\n      \u003CSuspense fallback={null}>\n        \u003CThreeJsBackground \u002F>\n      \u003C\u002FSuspense>\n    \u003C\u002Fdiv>\n  )\n}\n```\n\n### Virtualization for Long Lists\n\n```typescript\nimport { useVirtualizer } from '@tanstack\u002Freact-virtual'\n\nexport function VirtualMarketList({ markets }: { markets: Market[] }) {\n  const parentRef = useRef\u003CHTMLDivElement>(null)\n\n  const virtualizer = useVirtualizer({\n    count: markets.length,\n    getScrollElement: () => parentRef.current,\n    estimateSize: () => 100,  \u002F\u002F Estimated row height\n    overscan: 5  \u002F\u002F Extra items to render\n  })\n\n  return (\n    \u003Cdiv ref={parentRef} style={{ height: '600px', overflow: 'auto' }}>\n      \u003Cdiv\n        style={{\n          height: `${virtualizer.getTotalSize()}px`,\n          position: 'relative'\n        }}\n      >\n        {virtualizer.getVirtualItems().map(virtualRow => (\n          \u003Cdiv\n            key={virtualRow.index}\n            style={{\n              position: 'absolute',\n              top: 0,\n              left: 0,\n              width: '100%',\n              height: `${virtualRow.size}px`,\n              transform: `translateY(${virtualRow.start}px)`\n            }}\n          >\n            \u003CMarketCard market={markets[virtualRow.index]} \u002F>\n          \u003C\u002Fdiv>\n        ))}\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  )\n}\n```\n\n## Form Handling Patterns\n\n### Controlled Form with Validation\n\n```typescript\ninterface FormData {\n  name: string\n  description: string\n  endDate: string\n}\n\ninterface FormErrors {\n  name?: string\n  description?: string\n  endDate?: string\n}\n\nexport function CreateMarketForm() {\n  const [formData, setFormData] = useState\u003CFormData>({\n    name: '',\n    description: '',\n    endDate: ''\n  })\n\n  const [errors, setErrors] = useState\u003CFormErrors>({})\n\n  const validate = (): boolean => {\n    const newErrors: FormErrors = {}\n\n    if (!formData.name.trim()) {\n      newErrors.name = 'Name is required'\n    } else if (formData.name.length > 200) {\n      newErrors.name = 'Name must be under 200 characters'\n    }\n\n    if (!formData.description.trim()) {\n      newErrors.description = 'Description is required'\n    }\n\n    if (!formData.endDate) {\n      newErrors.endDate = 'End date is required'\n    }\n\n    setErrors(newErrors)\n    return Object.keys(newErrors).length === 0\n  }\n\n  const handleSubmit = async (e: React.FormEvent) => {\n    e.preventDefault()\n\n    if (!validate()) return\n\n    try {\n      await createMarket(formData)\n      \u002F\u002F Success handling\n    } catch (error) {\n      \u002F\u002F Error handling\n    }\n  }\n\n  return (\n    \u003Cform onSubmit={handleSubmit}>\n      \u003Cinput\n        value={formData.name}\n        onChange={e => setFormData(prev => ({ ...prev, name: e.target.value }))}\n        placeholder=\"Market name\"\n      \u002F>\n      {errors.name && \u003Cspan className=\"error\">{errors.name}\u003C\u002Fspan>}\n\n      {\u002F* Other fields *\u002F}\n\n      \u003Cbutton type=\"submit\">Create Market\u003C\u002Fbutton>\n    \u003C\u002Fform>\n  )\n}\n```\n\n## Error Boundary Pattern\n\n```typescript\ninterface ErrorBoundaryState {\n  hasError: boolean\n  error: Error | null\n}\n\nexport class ErrorBoundary extends React.Component\u003C\n  { children: React.ReactNode },\n  ErrorBoundaryState\n> {\n  state: ErrorBoundaryState = {\n    hasError: false,\n    error: null\n  }\n\n  static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n    return { hasError: true, error }\n  }\n\n  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {\n    console.error('Error boundary caught:', error, errorInfo)\n  }\n\n  render() {\n    if (this.state.hasError) {\n      return (\n        \u003Cdiv className=\"error-fallback\">\n          \u003Ch2>Something went wrong\u003C\u002Fh2>\n          \u003Cp>{this.state.error?.message}\u003C\u002Fp>\n          \u003Cbutton onClick={() => this.setState({ hasError: false })}>\n            Try again\n          \u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      )\n    }\n\n    return this.props.children\n  }\n}\n\n\u002F\u002F Usage\n\u003CErrorBoundary>\n  \u003CApp \u002F>\n\u003C\u002FErrorBoundary>\n```\n\n## Animation Patterns\n\n### Framer Motion Animations\n\n```typescript\nimport { motion, AnimatePresence } from 'framer-motion'\n\n\u002F\u002F ✅ List animations\nexport function AnimatedMarketList({ markets }: { markets: Market[] }) {\n  return (\n    \u003CAnimatePresence>\n      {markets.map(market => (\n        \u003Cmotion.div\n          key={market.id}\n          initial={{ opacity: 0, y: 20 }}\n          animate={{ opacity: 1, y: 0 }}\n          exit={{ opacity: 0, y: -20 }}\n          transition={{ duration: 0.3 }}\n        >\n          \u003CMarketCard market={market} \u002F>\n        \u003C\u002Fmotion.div>\n      ))}\n    \u003C\u002FAnimatePresence>\n  )\n}\n\n\u002F\u002F ✅ Modal animations\nexport function Modal({ isOpen, onClose, children }: ModalProps) {\n  return (\n    \u003CAnimatePresence>\n      {isOpen && (\n        \u003C>\n          \u003Cmotion.div\n            className=\"modal-overlay\"\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            exit={{ opacity: 0 }}\n            onClick={onClose}\n          \u002F>\n          \u003Cmotion.div\n            className=\"modal-content\"\n            initial={{ opacity: 0, scale: 0.9, y: 20 }}\n            animate={{ opacity: 1, scale: 1, y: 0 }}\n            exit={{ opacity: 0, scale: 0.9, y: 20 }}\n          >\n            {children}\n          \u003C\u002Fmotion.div>\n        \u003C\u002F>\n      )}\n    \u003C\u002FAnimatePresence>\n  )\n}\n```\n\n## Accessibility Patterns\n\n### Keyboard Navigation\n\n```typescript\nexport function Dropdown({ options, onSelect }: DropdownProps) {\n  const [isOpen, setIsOpen] = useState(false)\n  const [activeIndex, setActiveIndex] = useState(0)\n\n  const handleKeyDown = (e: React.KeyboardEvent) => {\n    switch (e.key) {\n      case 'ArrowDown':\n        e.preventDefault()\n        setActiveIndex(i => Math.min(i + 1, options.length - 1))\n        break\n      case 'ArrowUp':\n        e.preventDefault()\n        setActiveIndex(i => Math.max(i - 1, 0))\n        break\n      case 'Enter':\n        e.preventDefault()\n        onSelect(options[activeIndex])\n        setIsOpen(false)\n        break\n      case 'Escape':\n        setIsOpen(false)\n        break\n    }\n  }\n\n  return (\n    \u003Cdiv\n      role=\"combobox\"\n      aria-expanded={isOpen}\n      aria-haspopup=\"listbox\"\n      onKeyDown={handleKeyDown}\n    >\n      {\u002F* Dropdown implementation *\u002F}\n    \u003C\u002Fdiv>\n  )\n}\n```\n\n### Focus Management\n\n```typescript\nexport function Modal({ isOpen, onClose, children }: ModalProps) {\n  const modalRef = useRef\u003CHTMLDivElement>(null)\n  const previousFocusRef = useRef\u003CHTMLElement | null>(null)\n\n  useEffect(() => {\n    if (isOpen) {\n      \u002F\u002F Save currently focused element\n      previousFocusRef.current = document.activeElement as HTMLElement\n\n      \u002F\u002F Focus modal\n      modalRef.current?.focus()\n    } else {\n      \u002F\u002F Restore focus when closing\n      previousFocusRef.current?.focus()\n    }\n  }, [isOpen])\n\n  return isOpen ? (\n    \u003Cdiv\n      ref={modalRef}\n      role=\"dialog\"\n      aria-modal=\"true\"\n      tabIndex={-1}\n      onKeyDown={e => e.key === 'Escape' && onClose()}\n    >\n      {children}\n    \u003C\u002Fdiv>\n  ) : null\n}\n```\n\n**Remember**: Modern frontend patterns enable maintainable, performant user interfaces. Choose patterns that fit your project complexity.","# Frontend Development Patterns\n\nModern frontend patterns for React, Next.js, and performant user interfaces.\n\n## Component Patterns\n\n### Composition Over Inheritance\n\n```typescript\n\u002F\u002F ✅ GOOD: Component composition\ninterface CardProps {\n  children: React.ReactNode\n  variant?: 'default' | 'outlined'\n}\n\nexport function Card({ children, variant = 'default' }: CardProps) {\n  return \u003Cdiv className={`card card-${variant}`}>{children}\u003C\u002Fdiv>\n}\n\nexport function CardHeader({ children }: { children: React.ReactNode }) {\n  return \u003Cdiv className=\"card-header\">{children}\u003C\u002Fdiv>\n}\n\nexport function CardBody({ children }: { children: React.ReactNode }) {\n  return \u003Cdiv className=\"card-body\">{children}\u003C\u002Fdiv>\n}\n\n\u002F\u002F Usage\n\u003CCard>\n  \u003CCardHeader>Title\u003C\u002FCardHeader>\n  \u003CCardBody>Content\u003C\u002FCardBody>\n\u003C\u002FCard>\n```\n\n### Compound Components\n\n```typescript\ninterface TabsContextValue {\n  activeTab: string\n  setActiveTab: (tab: string) => void\n}\n\nconst TabsContext = createContext\u003CTabsContextValue | undefined>(undefined)\n\nexport function Tabs({ children, defaultTab }: {\n  children: React.ReactNode\n  defaultTab: string\n}) {\n  const [activeTab, setActiveTab] = useState(defaultTab)\n\n  return (\n    \u003CTabsContext.Provider value={{ activeTab, setActiveTab }}>\n      {children}\n    \u003C\u002FTabsContext.Provider>\n  )\n}\n\nexport function TabList({ children }: { children: React.ReactNode }) {\n  return \u003Cdiv className=\"tab-list\">{children}\u003C\u002Fdiv>\n}\n\nexport function Tab({ id, children }: { id: string, children: React.ReactNode }) {\n  const context = useContext(TabsContext)\n  if (!context) throw new Error('Tab must be used within Tabs')\n\n  return (\n    \u003Cbutton\n      className={context.activeTab === id ? 'active' : ''}\n      onClick={() => context.setActiveTab(id)}\n    >\n      {children}\n    \u003C\u002Fbutton>\n  )\n}\n\n\u002F\u002F Usage\n\u003CTabs defaultTab=\"overview\">\n  \u003CTabList>\n    \u003CTab id=\"overview\">Overview\u003C\u002FTab>\n    \u003CTab id=\"details\">Details\u003C\u002FTab>\n  \u003C\u002FTabList>\n\u003C\u002FTabs>\n```\n\n### Render Props Pattern\n\n```typescript\ninterface DataLoaderProps\u003CT> {\n  url: string\n  children: (data: T | null, loading: boolean, error: Error | null) => React.ReactNode\n}\n\nexport function DataLoader\u003CT>({ url, children }: DataLoaderProps\u003CT>) {\n  const [data, setData] = useState\u003CT | null>(null)\n  const [loading, setLoading] = useState(true)\n  const [error, setError] = useState\u003CError | null>(null)\n\n  useEffect(() => {\n    fetch(url)\n      .then(res => res.json())\n      .then(setData)\n      .catch(setError)\n      .finally(() => setLoading(false))\n  }, [url])\n\n  return \u003C>{children(data, loading, error)}\u003C\u002F>\n}\n\n\u002F\u002F Usage\n\u003CDataLoader\u003CMarket[]> url=\"\u002Fapi\u002Fmarkets\">\n  {(markets, loading, error) => {\n    if (loading) return \u003CSpinner \u002F>\n    if (error) return \u003CError error={error} \u002F>\n    return \u003CMarketList markets={markets!} \u002F>\n  }}\n\u003C\u002FDataLoader>\n```\n\n## Custom Hooks Patterns\n\n### State Management Hook\n\n```typescript\nexport function useToggle(initialValue = false): [boolean, () => void] {\n  const [value, setValue] = useState(initialValue)\n\n  const toggle = useCallback(() => {\n    setValue(v => !v)\n  }, [])\n\n  return [value, toggle]\n}\n\n\u002F\u002F Usage\nconst [isOpen, toggleOpen] = useToggle()\n```\n\n### Async Data Fetching Hook\n\n```typescript\ninterface UseQueryOptions\u003CT> {\n  onSuccess?: (data: T) => void\n  onError?: (error: Error) => void\n  enabled?: boolean\n}\n\nexport function useQuery\u003CT>(\n  key: string,\n  fetcher: () => Promise\u003CT>,\n  options?: UseQueryOptions\u003CT>\n) {\n  const [data, setData] = useState\u003CT | null>(null)\n  const [error, setError] = useState\u003CError | null>(null)\n  const [loading, setLoading] = useState(false)\n\n  const refetch = useCallback(async () => {\n    setLoading(true)\n    setError(null)\n\n    try {\n      const result = await fetcher()\n      setData(result)\n      options?.onSuccess?.(result)\n    } catch (err) {\n      const error = err as Error\n      setError(error)\n      options?.onError?.(error)\n    } finally {\n      setLoading(false)\n    }\n  }, [fetcher, options])\n\n  useEffect(() => {\n    if (options?.enabled !== false) {\n      refetch()\n    }\n  }, [key, refetch, options?.enabled])\n\n  return { data, error, loading, refetch }\n}\n\n\u002F\u002F Usage\nconst { data: markets, loading, error, refetch } = useQuery(\n  'markets',\n  () => fetch('\u002Fapi\u002Fmarkets').then(r => r.json()),\n  {\n    onSuccess: data => console.log('Fetched', data.length, 'markets'),\n    onError: err => console.error('Failed:', err)\n  }\n)\n```\n\n### Debounce Hook\n\n```typescript\nexport function useDebounce\u003CT>(value: T, delay: number): T {\n  const [debouncedValue, setDebouncedValue] = useState\u003CT>(value)\n\n  useEffect(() => {\n    const handler = setTimeout(() => {\n      setDebouncedValue(value)\n    }, delay)\n\n    return () => clearTimeout(handler)\n  }, [value, delay])\n\n  return debouncedValue\n}\n\n\u002F\u002F Usage\nconst [searchQuery, setSearchQuery] = useState('')\nconst debouncedQuery = useDebounce(searchQuery, 500)\n\nuseEffect(() => {\n  if (debouncedQuery) {\n    performSearch(debouncedQuery)\n  }\n}, [debouncedQuery])\n```\n\n## State Management Patterns\n\n### Context + Reducer Pattern\n\n```typescript\ninterface State {\n  markets: Market[]\n  selectedMarket: Market | null\n  loading: boolean\n}\n\ntype Action =\n  | { type: 'SET_MARKETS'; payload: Market[] }\n  | { type: 'SELECT_MARKET'; payload: Market }\n  | { type: 'SET_LOADING'; payload: boolean }\n\nfunction reducer(state: State, action: Action): State {\n  switch (action.type) {\n    case 'SET_MARKETS':\n      return { ...state, markets: action.payload }\n    case 'SELECT_MARKET':\n      return { ...state, selectedMarket: action.payload }\n    case 'SET_LOADING':\n      return { ...state, loading: action.payload }\n    default:\n      return state\n  }\n}\n\nconst MarketContext = createContext\u003C{\n  state: State\n  dispatch: Dispatch\u003CAction>\n} | undefined>(undefined)\n\nexport function MarketProvider({ children }: { children: React.ReactNode }) {\n  const [state, dispatch] = useReducer(reducer, {\n    markets: [],\n    selectedMarket: null,\n    loading: false\n  })\n\n  return (\n    \u003CMarketContext.Provider value={{ state, dispatch }}>\n      {children}\n    \u003C\u002FMarketContext.Provider>\n  )\n}\n\nexport function useMarkets() {\n  const context = useContext(MarketContext)\n  if (!context) throw new Error('useMarkets must be used within MarketProvider')\n  return context\n}\n```\n\n## Performance Optimization\n\n### Memoization\n\n```typescript\n\u002F\u002F ✅ useMemo for expensive computations\nconst sortedMarkets = useMemo(() => {\n  return markets.sort((a, b) => b.volume - a.volume)\n}, [markets])\n\n\u002F\u002F ✅ useCallback for functions passed to children\nconst handleSearch = useCallback((query: string) => {\n  setSearchQuery(query)\n}, [])\n\n\u002F\u002F ✅ React.memo for pure components\nexport const MarketCard = React.memo\u003CMarketCardProps>(({ market }) => {\n  return (\n    \u003Cdiv className=\"market-card\">\n      \u003Ch3>{market.name}\u003C\u002Fh3>\n      \u003Cp>{market.description}\u003C\u002Fp>\n    \u003C\u002Fdiv>\n  )\n})\n```\n\n### Code Splitting & Lazy Loading\n\n```typescript\nimport { lazy, Suspense } from 'react'\n\n\u002F\u002F ✅ Lazy load heavy components\nconst HeavyChart = lazy(() => import('.\u002FHeavyChart'))\nconst ThreeJsBackground = lazy(() => import('.\u002FThreeJsBackground'))\n\nexport function Dashboard() {\n  return (\n    \u003Cdiv>\n      \u003CSuspense fallback={\u003CChartSkeleton \u002F>}>\n        \u003CHeavyChart data={data} \u002F>\n      \u003C\u002FSuspense>\n\n      \u003CSuspense fallback={null}>\n        \u003CThreeJsBackground \u002F>\n      \u003C\u002FSuspense>\n    \u003C\u002Fdiv>\n  )\n}\n```\n\n### Virtualization for Long Lists\n\n```typescript\nimport { useVirtualizer } from '@tanstack\u002Freact-virtual'\n\nexport function VirtualMarketList({ markets }: { markets: Market[] }) {\n  const parentRef = useRef\u003CHTMLDivElement>(null)\n\n  const virtualizer = useVirtualizer({\n    count: markets.length,\n    getScrollElement: () => parentRef.current,\n    estimateSize: () => 100,  \u002F\u002F Estimated row height\n    overscan: 5  \u002F\u002F Extra items to render\n  })\n\n  return (\n    \u003Cdiv ref={parentRef} style={{ height: '600px', overflow: 'auto' }}>\n      \u003Cdiv\n        style={{\n          height: `${virtualizer.getTotalSize()}px`,\n          position: 'relative'\n        }}\n      >\n        {virtualizer.getVirtualItems().map(virtualRow => (\n          \u003Cdiv\n            key={virtualRow.index}\n            style={{\n              position: 'absolute',\n              top: 0,\n              left: 0,\n              width: '100%',\n              height: `${virtualRow.size}px`,\n              transform: `translateY(${virtualRow.start}px)`\n            }}\n          >\n            \u003CMarketCard market={markets[virtualRow.index]} \u002F>\n          \u003C\u002Fdiv>\n        ))}\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  )\n}\n```\n\n## Form Handling Patterns\n\n### Controlled Form with Validation\n\n```typescript\ninterface FormData {\n  name: string\n  description: string\n  endDate: string\n}\n\ninterface FormErrors {\n  name?: string\n  description?: string\n  endDate?: string\n}\n\nexport function CreateMarketForm() {\n  const [formData, setFormData] = useState\u003CFormData>({\n    name: '',\n    description: '',\n    endDate: ''\n  })\n\n  const [errors, setErrors] = useState\u003CFormErrors>({})\n\n  const validate = (): boolean => {\n    const newErrors: FormErrors = {}\n\n    if (!formData.name.trim()) {\n      newErrors.name = 'Name is required'\n    } else if (formData.name.length > 200) {\n      newErrors.name = 'Name must be under 200 characters'\n    }\n\n    if (!formData.description.trim()) {\n      newErrors.description = 'Description is required'\n    }\n\n    if (!formData.endDate) {\n      newErrors.endDate = 'End date is required'\n    }\n\n    setErrors(newErrors)\n    return Object.keys(newErrors).length === 0\n  }\n\n  const handleSubmit = async (e: React.FormEvent) => {\n    e.preventDefault()\n\n    if (!validate()) return\n\n    try {\n      await createMarket(formData)\n      \u002F\u002F Success handling\n    } catch (error) {\n      \u002F\u002F Error handling\n    }\n  }\n\n  return (\n    \u003Cform onSubmit={handleSubmit}>\n      \u003Cinput\n        value={formData.name}\n        onChange={e => setFormData(prev => ({ ...prev, name: e.target.value }))}\n        placeholder=\"Market name\"\n      \u002F>\n      {errors.name && \u003Cspan className=\"error\">{errors.name}\u003C\u002Fspan>}\n\n      {\u002F* Other fields *\u002F}\n\n      \u003Cbutton type=\"submit\">Create Market\u003C\u002Fbutton>\n    \u003C\u002Fform>\n  )\n}\n```\n\n## Error Boundary Pattern\n\n```typescript\ninterface ErrorBoundaryState {\n  hasError: boolean\n  error: Error | null\n}\n\nexport class ErrorBoundary extends React.Component\u003C\n  { children: React.ReactNode },\n  ErrorBoundaryState\n> {\n  state: ErrorBoundaryState = {\n    hasError: false,\n    error: null\n  }\n\n  static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n    return { hasError: true, error }\n  }\n\n  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {\n    console.error('Error boundary caught:', error, errorInfo)\n  }\n\n  render() {\n    if (this.state.hasError) {\n      return (\n        \u003Cdiv className=\"error-fallback\">\n          \u003Ch2>Something went wrong\u003C\u002Fh2>\n          \u003Cp>{this.state.error?.message}\u003C\u002Fp>\n          \u003Cbutton onClick={() => this.setState({ hasError: false })}>\n            Try again\n          \u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      )\n    }\n\n    return this.props.children\n  }\n}\n\n\u002F\u002F Usage\n\u003CErrorBoundary>\n  \u003CApp \u002F>\n\u003C\u002FErrorBoundary>\n```\n\n## Animation Patterns\n\n### Framer Motion Animations\n\n```typescript\nimport { motion, AnimatePresence } from 'framer-motion'\n\n\u002F\u002F ✅ List animations\nexport function AnimatedMarketList({ markets }: { markets: Market[] }) {\n  return (\n    \u003CAnimatePresence>\n      {markets.map(market => (\n        \u003Cmotion.div\n          key={market.id}\n          initial={{ opacity: 0, y: 20 }}\n          animate={{ opacity: 1, y: 0 }}\n          exit={{ opacity: 0, y: -20 }}\n          transition={{ duration: 0.3 }}\n        >\n          \u003CMarketCard market={market} \u002F>\n        \u003C\u002Fmotion.div>\n      ))}\n    \u003C\u002FAnimatePresence>\n  )\n}\n\n\u002F\u002F ✅ Modal animations\nexport function Modal({ isOpen, onClose, children }: ModalProps) {\n  return (\n    \u003CAnimatePresence>\n      {isOpen && (\n        \u003C>\n          \u003Cmotion.div\n            className=\"modal-overlay\"\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            exit={{ opacity: 0 }}\n            onClick={onClose}\n          \u002F>\n          \u003Cmotion.div\n            className=\"modal-content\"\n            initial={{ opacity: 0, scale: 0.9, y: 20 }}\n            animate={{ opacity: 1, scale: 1, y: 0 }}\n            exit={{ opacity: 0, scale: 0.9, y: 20 }}\n          >\n            {children}\n          \u003C\u002Fmotion.div>\n        \u003C\u002F>\n      )}\n    \u003C\u002FAnimatePresence>\n  )\n}\n```\n\n## Accessibility Patterns\n\n### Keyboard Navigation\n\n```typescript\nexport function Dropdown({ options, onSelect }: DropdownProps) {\n  const [isOpen, setIsOpen] = useState(false)\n  const [activeIndex, setActiveIndex] = useState(0)\n\n  const handleKeyDown = (e: React.KeyboardEvent) => {\n    switch (e.key) {\n      case 'ArrowDown':\n        e.preventDefault()\n        setActiveIndex(i => Math.min(i + 1, options.length - 1))\n        break\n      case 'ArrowUp':\n        e.preventDefault()\n        setActiveIndex(i => Math.max(i - 1, 0))\n        break\n      case 'Enter':\n        e.preventDefault()\n        onSelect(options[activeIndex])\n        setIsOpen(false)\n        break\n      case 'Escape':\n        setIsOpen(false)\n        break\n    }\n  }\n\n  return (\n    \u003Cdiv\n      role=\"combobox\"\n      aria-expanded={isOpen}\n      aria-haspopup=\"listbox\"\n      onKeyDown={handleKeyDown}\n    >\n      {\u002F* Dropdown implementation *\u002F}\n    \u003C\u002Fdiv>\n  )\n}\n```\n\n### Focus Management\n\n```typescript\nexport function Modal({ isOpen, onClose, children }: ModalProps) {\n  const modalRef = useRef\u003CHTMLDivElement>(null)\n  const previousFocusRef = useRef\u003CHTMLElement | null>(null)\n\n  useEffect(() => {\n    if (isOpen) {\n      \u002F\u002F Save currently focused element\n      previousFocusRef.current = document.activeElement as HTMLElement\n\n      \u002F\u002F Focus modal\n      modalRef.current?.focus()\n    } else {\n      \u002F\u002F Restore focus when closing\n      previousFocusRef.current?.focus()\n    }\n  }, [isOpen])\n\n  return isOpen ? (\n    \u003Cdiv\n      ref={modalRef}\n      role=\"dialog\"\n      aria-modal=\"true\"\n      tabIndex={-1}\n      onKeyDown={e => e.key === 'Escape' && onClose()}\n    >\n      {children}\n    \u003C\u002Fdiv>\n  ) : null\n}\n```\n\n**Remember**: Modern frontend patterns enable maintainable, performant user interfaces. Choose patterns that fit your project complexity.",{"name":5,"author":46,"version":47,"description":7},"affaan-m","1.0","main","33d99efaac9ea5758fc27120b467eca96ad020d9",".agent\u002Fskills\u002Fcc-skill-frontend-patterns","https:\u002F\u002Fgithub.com\u002FEthanSheehan\u002FGrid-Sentinel","https:\u002F\u002Fgithub.com\u002FEthanSheehan","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fethan-sheehan\u002F","Aerospace Engineering Student at the University of Bristol \u002F\u002F Propulsion Lead at HyPower Bristol","2026-05-22 21:19:23",{"source":8,"skillName":5,"commands":57,"prompt":67,"zipAvailable":68},[58,61,64],{"tool":59,"command":60},"npx","npx skills add EthanSheehan\u002FGrid-Sentinel --skill frontend-patterns",{"tool":62,"command":63},"bunx","bunx skills add EthanSheehan\u002FGrid-Sentinel --skill frontend-patterns",{"tool":65,"command":66},"pnpm","pnpm dlx skills add EthanSheehan\u002FGrid-Sentinel --skill frontend-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FEthanSheehan\u002FGrid-Sentinel\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fcc-skill-frontend-patterns\u002FSKILL.md",true,[],[71,100,131,151,165,190],{"skillNo":72,"name":73,"nameZh":6,"description":74,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":75,"categories":76,"keywords":80,"publishedAt":41},"01M6DY3X97YDSKHCCZG9KMASHA","zapier-make-patterns","No-code automation democratizes workflow building. Zapier and Make (formerly Integromat) let non-developers automate business processes without writing code. But no-code doesn't mean no-complexity - these platforms have their own patterns, pitfalls, and breaking points.  This skill covers when to use which platform, how to build reliable automations, and when to graduate to code-based solutions. Key insight: Zapier optimizes for simplicity and integrations (7000+ apps), Make optimizes for power","https:\u002F\u002Fgithub.com\u002FEthanSheehan\u002FGrid-Sentinel\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fzapier-make-patterns\u002FSKILL.md",[77],{"categoryNo":78,"categoryName":79,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[81,24,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99],"zapier make patterns","workflow","integrations","how to","apps","platform","but","build","complexity","power","simplicity","use","business","automate","how","apache","code","automation","writing",{"skillNo":101,"name":102,"nameZh":6,"description":103,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":104,"categories":105,"keywords":110,"publishedAt":41},"01M6DY3SVP128ZZPF2478H9JYZ","Cross-Site Scripting and HTML Injection Testing","This skill should be used when the user asks to \"test for XSS vulnerabilities\", \"perform cross-site scripting attacks\", \"identify HTML injection flaws\", \"exploit client-side injection vulnerabilities\", \"steal cookies via XSS\", or \"bypass content security policies\". It provides comprehensive techniques for detecting, exploiting, and understanding XSS and HTML injection attack vectors in web applications.","https:\u002F\u002Fgithub.com\u002FEthanSheehan\u002FGrid-Sentinel\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fxss-html-injection\u002FSKILL.md",[106,109],{"categoryNo":107,"categoryName":108,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130],"html injection testing","Cross Site Scripting and HTML Injection Testing","injection","scripting","site","html","testing","exploit","user","applications","xss","cookies","content","web","test","vectors","via","steal","security","vulnerabilities",{"skillNo":132,"name":133,"nameZh":6,"description":134,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":135,"categories":136,"keywords":146,"publishedAt":41},"01M6DY3D694G80Y5N79CD1J575","writing-skills","Use when creating new skills, editing existing skills, or verifying skills work before deployment","https:\u002F\u002Fgithub.com\u002FEthanSheehan\u002FGrid-Sentinel\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fwriting-skills\u002FSKILL.md",[137,138,141],{"categoryNo":107,"categoryName":108,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":139,"categoryName":140,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":142,"categoryName":143,"taxonomyType":144,"taxonomyTypeDesc":145},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[99,147,148,92,149,150],"writing skills","deployment","editing","work",{"skillNo":152,"name":153,"nameZh":6,"description":154,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":155,"categories":156,"keywords":159,"publishedAt":41},"01M6DY3A7BM31W5Q2QARW00JHS","writing-plans","Use when you have a spec or requirements for a multi-step task, before touching code","https:\u002F\u002Fgithub.com\u002FEthanSheehan\u002FGrid-Sentinel\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fwriting-plans\u002FSKILL.md",[157,158],{"categoryNo":139,"categoryName":140,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":142,"categoryName":143,"taxonomyType":144,"taxonomyTypeDesc":145},[160,99,161,162,163,92,97,164],"writing plans","plans","requirements","task","spec",{"skillNo":166,"name":167,"nameZh":6,"description":168,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":169,"categories":170,"keywords":172,"publishedAt":41},"01M6DY36NSATM95HR7HMVZJYB3","workflow-automation","Workflow automation is the infrastructure that makes AI agents reliable. Without durable execution, a network hiccup during a 10-step payment flow means lost money and angry customers. With it, workflows resume exactly where they left off.  This skill covers the platforms (n8n, Temporal, Inngest) and patterns (sequential, parallel, orchestrator-worker) that turn brittle scripts into production-grade automation.  Key insight: The platforms make different tradeoffs. n8n optimizes for accessibility","https:\u002F\u002Fgithub.com\u002FEthanSheehan\u002FGrid-Sentinel\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fworkflow-automation\u002FSKILL.md",[171],{"categoryNo":78,"categoryName":79,"taxonomyType":21,"taxonomyTypeDesc":22},[173,98,82,174,175,176,96,177,178,179,180,181,182,183,184,185,186,187,188,189],"Workflow Automation","Production","flow","network","workflows","accessibility","ai agents","execution","scripts","worker","payment","n8n","money","resume","orchestrator","parallel","inngest",{"skillNo":191,"name":192,"nameZh":6,"description":193,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":194,"categories":195,"keywords":197,"publishedAt":41},"01M6DY32QTGD80MQHJ8TPDH53H","WordPress Penetration Testing","This skill should be used when the user asks to \"pentest WordPress sites\", \"scan WordPress for vulnerabilities\", \"enumerate WordPress users, themes, or plugins\", \"exploit WordPress vulnerabilities\", or \"use WPScan\". It provides comprehensive WordPress security assessment methodologies.","https:\u002F\u002Fgithub.com\u002FEthanSheehan\u002FGrid-Sentinel\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Fwordpress-penetration-testing\u002FSKILL.md",[196],{"categoryNo":107,"categoryName":108,"taxonomyType":21,"taxonomyTypeDesc":22},[117,192,198,199,200,201,202,203,118,92,119,204,205,130,129],"penetration testing","wordpress","security assessment","sites","scan","pentest","plugins","assessment"]