開発
#react
frontend-patterns
Patrones de desarrollo frontend para React, Next.js, gestión de estado, optimización de rendimiento y buenas prácticas de UI.
DeepseekModel
キュレーション済みスキル
品質 優秀 · 90
v1.0.0
取得
https://deepseekmodel.com/api/download.php?id=affaan-m-ecc-docs-es-skills-frontend-patterns-skill-md&format=skill
ダウンロード .skill
標準形式。system_prompt と model_config を収録し、任意の Agent で利用可能
.skill ファイルの system_prompt フィールドの実際の内容。
name frontend-patterns description Patrones de desarrollo frontend para React, Next.js, gestión de estado, optimización de rendimiento y buenas prácticas de UI. origin ECC Patrones de Desarrollo Frontend Patrones modernos de frontend para React, Next.js e interfaces de usuario de alto rendimiento. Cuándo Activar Construir componentes React (composición, props, renderizado) Gestionar estado (useState, useReducer, Zustand, Context) Implementar obtención de datos (SWR, React Query, server components) Optimizar rendimiento (memoización, virtualización, code splitting) Trabajar con formularios (validación, inputs controlados, esquemas Zod) Manejar routing y navegación del lado del cliente Construir patrones de UI accesibles y responsivos Patrones de Componentes Composición sobre Herencia // PASS: BIEN: Composición de componentes interface CardProps { children : React . ReactNode variant ?: 'default' | 'outlined' } export function Card ( { children, variant = 'default' }: CardProps ) { return < div className = { ` card card- ${ variant }`}> {children} </ div > } export function CardHeader ( { children }: { children: React.ReactNode } ) { return < div className = "card-header" > {children} </ div > } export function CardBody ( { children }: { children: React.ReactNode } ) { return < div className = "card-body" > {children} </ div > } // Uso < Card > < CardHeader > Title </ CardHeader > < CardBody > Content </ CardBody > </ Card > Compound Components interface TabsContextValue { activeTab : string setActiveTab : ( tab : string ) => void } const TabsContext = createContext< TabsContextValue | undefined >( undefined ) export function Tabs ( { children, defaultTab }: { children: React.ReactNode defaultTab: string } ) { const [activeTab, setActiveTab] = useState (defaultTab) return ( < TabsContext.Provider value = {{ activeTab , setActiveTab }}> {children} </ TabsContext.Provider > ) } export function TabList ( { children }: { children: React.ReactNode } ) { return < div className = "tab-list" > {children} </ div > } export function Tab ( { id, children }: { id: string , children: React.ReactNode } ) { const context = useContext ( TabsContext ) if (!context) throw new Error ( 'Tab must be used within Tabs' ) return ( < button className = {context.activeTab === id ? ' active ' : ''} onClick = {() => context.setActiveTab(id)} > {children} </ button > ) } // Uso < Tabs defaultTab= "overview" > < TabList > < Tab id = "overview" > Overview </ Tab > < Tab id = "details" > Details </ Tab > </ TabList > </ Tabs > Patrón Render Props interface DataLoaderProps <T> { url : string children : ( data : T | null , loading : boolean , error : Error | null ) => React . ReactNode } export function DataLoader <T>({ url, children }: DataLoaderProps <T>) { const [data, setData] = useState<T | null >( null ) const [loading, setLoading] = useState ( true ) const [error, setError] = useState< Error | null >( null ) useEffect ( () => { fetch (url) . then ( res => res. json ()) . then (setData) . catch (setError) . finally ( () => setLoading ( false )) }, [url]) return <> {children(data, loading, error)} </> } // Uso < DataLoader < Market []> url= "/api/markets" > { ( markets, loading, error ) => { if (loading) return < Spinner /> if (error) return < Error error = {error} /> return < MarketList markets = {markets!} /> }} </ DataLoader > Patrones de Custom Hooks Hook de Gestión de Estado export function useToggle ( initialValue = false ): [ boolean , () => void ] { const [value, setValue] = useState (initialValue) const toggle = useCallback ( () => { setValue ( v => !v) }, []) return [value, toggle] } // Uso const [isOpen, toggleOpen] = useToggle () Hook de Obtención de Datos Asíncrona interface UseQueryOptions <T> { onSuccess ?: ( data : T ) => void onError ?: ( error : Error ) => void enabled ?: boolean } export function useQuery<T>( key : string , fetcher : () => Promise <T>, options ?: UseQueryOptions <T> ) { const [data, setData] = useState<T | null >( null ) const [error, setError] = useState< Error | null >( null ) const [loading, setLoading] = useState ( false ) const refetch = useCallback ( async () => { setLoading ( true ) setError ( null ) try { const result = await fetcher () setData (result) options?. onSuccess ?.(result) } catch (err) { const error = err as Error setError (error) options?. onError ?.(error) } finally { setLoading ( false ) } }, [fetcher, options]) useEffect ( () => { if (options?. enabled !== false ) { refetch () } }, [key, refetch, options?. enabled ]) return { data, error, loading, refetch } } // Uso const { data : markets, loading, error, refetch } = useQuery ( 'markets' , () => fetch ( '/api/markets' ). then ( r => r. json ()), { onSuccess : data => console . log ( 'Fetched' , data. length , 'markets' ), onError : err => console . error ( 'Failed:' , err) } ) Hook de Debounce export function useDebounce<T>( value : T, delay : number ): T { const [debouncedValue, setDebouncedValue] = useState<T>(value) useEffect ( () => { const handler = setTimeout ( () => { setDebouncedValue (value) }, delay) return () => clearTimeout (handler) }, [value, delay]) return debouncedValue } // Uso const [searchQuery, setSearchQuery] = useState ( '' ) const debouncedQuery = useDebounce (searchQuery, 500 ) useEffect ( () => { if (debouncedQuery) { performSearch (debouncedQuery) } }, [debouncedQuery]) Patrones de Gestión de Estado Patrón Context + Reducer interface State { markets : Market [] selectedMarket : Market | null loading : boolean } type Action = | { type : 'SET_MARKETS' ; payload : Market [] } | { type : 'SELECT_MARKET' ; payload : Market } | { type : 'SET_LOADING' ; payload : boolean } function reducer ( state : State , action : Action ): State { switch (action. type ) { case 'SET_MARKETS' : return { ...state, markets : action. payload } case 'SELECT_MARKET' : return { ...state, selectedMarket : action. payload } case 'SET_LOADING' : return { ...state, loading : action. payload } default : return state } } const MarketContext = createContext<{ state : State dispatch : Dispatch < Action > } | undefined >( undefined ) export function MarketProvider ( { children }: { children: React.ReactNode } ) { const [state, dispatch] = useReducer (reducer, { markets : [], selectedMarket : null , loading : false }) return ( < MarketContext.Provider value = {{ state , dispatch }}> {children} </ MarketContext.Provider > ) } export function useMarkets ( ) { const context = useContext ( MarketContext ) if (!context) throw new Error ( 'useMarkets must be used within MarketProvider' ) return context } Optimización de Rendimiento Memoización // PASS: useMemo para cómputos costosos const sortedMarkets = useMemo ( () => { return markets. sort ( ( a, b ) => b. volume - a. volume ) }, [markets]) // PASS: useCallback para funciones pasadas a hijos const handleSearch = useCallback ( ( query : string ) => { setSearchQuery (query) }, []) // PASS: React.memo para componentes puros export const MarketCard = React . memo < MarketCardProps >( ( { market } ) => { return ( < div className = "market-card" > < h3 > {market.name} </ h3 > < p > {market.description} </ p > </ div > ) }) Code Splitting y Carga Diferida import { lazy, Suspense } from 'react' // PASS: Carga diferida de componentes pesados const HeavyChart = lazy ( () => import ( './HeavyChart' )) const ThreeJsBackground = lazy ( () => import ( './ThreeJsBackground' )) export function Dashboard ( ) { return ( < div > < Suspense fallback = { < ChartSkeleton /> }> < HeavyChart data = {data} /> </ Suspense > < Suspense fallback = {null} > < ThreeJsBackground /> </ Suspense > </ div > ) } Virtualización para Listas Largas import { useVirtualizer } from '@tanstack/react-virtual' export function VirtualMarketList ( { markets }: { markets: Market[] } ) { const parentRef = useRef< HTMLDivElement >( null ) const virtualizer = useVirtualizer ({ count : markets. length , getScrollElement : () => parentRef. current , estimateSize : () => 100 , // Altura estimada de fila overscan : 5 // Elementos extra a renderizar }) return ( < div ref = {parentRef} style = {{ height: ' 600px ', overflow: ' auto ' }}> < div style = {{ height: `${ virtualizer.getTotalSize ()} px `, position: ' relative ' }} > {virtualizer.getVirtualItems().map(virtualRow => ( < div key = {virtualRow.index} style = {{ position: ' absolute ', top: 0 , left: 0 , width: ' 100 %', height: `${ virtualRow.size } px `, transform: ` translateY (${ virtualRow.start } px )` }} > < MarketCard market = {markets[virtualRow.index]} /> </ div > ))} </ div > </ div > ) } Patrones de Manejo de Formularios Formulario Controlado con Validación interface FormData { name : string description : string endDate : string } interface FormErrors { name ?: string description ?: string endDate ?: string } export function CreateMarketForm ( ) { const [formData, setFormData] = useState< FormData >({ name : '' , description : '' , endDate : '' }) const [errors, setErrors] = useState< FormErrors >({}) const validate = (): boolean => { const newErrors : FormErrors = {} if (!formData. name . trim ()) { newErrors. name = 'Name is required' } else if (formData. name . length > 200 ) { newErrors. name = 'Name must be under 200 characters' } if (!formData. description . trim ()) { newErrors. description = 'Description is required' } if (!formData. endDate ) { newErrors. endDate = 'End date is required' } setErrors (newErrors) return Object . keys (newErrors). length === 0 } const handleSubmit = async ( e : React . FormEvent ) => { e. preventDefault () if (! validate ()) return try { await createMarket (formData) // Manejo de éxito } catch (error) { // Manejo de error } } return ( < form onSubmit = {handleSubmit} > < input value = {formData.name} onChange = {e => setFormData(prev => ({ ...prev, name: e.target.value }))} placeholder="Market name" />
このスキルを起動するキーワード。クリックでコピーできます。
このスキルにはトリガーワードがありません。
ダウンロードした .skill に含まれるフィールド。
| フィールド | 説明 |
|---|---|
| format | フォーマット識別子(skill/v1) |
| skill_id | スキル固有 ID |
| name | スキル名 |
| version | バージョン |
| description | 説明 |
| category | カテゴリ(配列) |
| trigger_words | トリガーワード |
| tags | タグ |
| source | ソース |
| source_url | ソース URL(本ページ) |
| exported_at | エクスポート日時(ダウンロード毎) |
| system_prompt | システムプロンプト本文 |
| model_config | モデル設定:provider / model / temperature / max_tokens / top_p |
| examples | サンプル |
| install_guide | 各プラットフォームの導入説明(Coze / Dify / Claude / カスタム) |