Skip to main content

frontend

Modern frontend development with React, Vue, and web technologies

ソース情報

リポジトリ
miles990/claude-software-skills
ソースの最終更新活動
2026年1月8日 05:30
検出された SKILL.md の言語
中国語
スター
26
フォーク
6

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
5 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
frontend
description
Modern frontend development with React, Vue, and web technologies
domain
development-stacks
version
1.1.0
tags
["react","vue","nextjs","typescript","css","state-management","bundlers"]
triggers
{"keywords":{"primary":["frontend","react","vue","nextjs","ui","web","component"],"secondary":["css","tailwind","state","hooks","spa","pwa","vite"]},"context_boost":["typescript","javascript","html","browser","client"],"context_penalty":["backend","server","database","api"],"priority":"high"}
collaboration
{"prerequisites":[{"skill":"typescript","reason":"Type-safe component development"}],"delegation_triggers":[{"trigger":"API integration or backend communication","delegate_to":"backend","context":"API endpoints, authentication flow"},{"trigger":"API response format questions","delegate_to":"api-design","context":"Expected data structures, error handling"},{"trigger":"Component or integration testing","delegate_to":"testing-strategies","context":"Testing library patterns, mocking APIs"}],"receives_context_from":[{"skill":"backend","receives":"[Truncated]"},{"skill":"api-design","receives":"[Truncated]"}],"provides_context_to":[{"skill":"testing-strategies","provides":"[Truncated]"},{"skill":"backend","provides":"[Truncated]"}]}
# Frontend Development ## Overview Modern frontend development patterns, frameworks, and best practices for building performant web applications. --- ## React Ecosystem ### Component Patterns ```tsx // Functional component with hooks import { useState, useEffect, useCallback, useMemo } from 'react'; interface UserListProps { initialFilter?: string; onSelect: (user: User) => void; } function UserList({ initialFilter = '', onSelect }: UserListProps) { const [users, setUsers] = useState<User[]>([]); const [filter, setFilter] = useState(initialFilter); const [loading, setLoading] = useState(true); // Memoized filtered list const filteredUsers = useMemo( () => users.filter(u => u.name.toLowerCase().includes(filter.toLowerCase())), [users, filter] ); // Stable callback reference const handleSelect = useCallback((user: User) => { onSelect(user); }, [onSelect]); useEffect(() => { async function fetchUsers() { setLoading(true); const data = await api.getUsers(); setUsers(data); setLoading(false); } fetchUsers(); }, []); if (loading) return <Skeleton count={5} />; return ( <div> <SearchInput value={filter} onChange={setFilter} /> {filteredUsers.map(user => ( <UserCard key={user.id} user={user} onClick={() => handleSelect(user)} /> ))} </div> ); } ``` ### Custom Hooks ```tsx // Data fetching hook function useFetch<T>(url: string) { const [data, setData] = useState<T | null>(null); const [error, setError] = useState<Error | null>(null); const [loading, setLoading] = useState(true); useEffect(() => { const controller = new AbortController(); async function fetchData() { try { setLoading(true); const response = await fetch(url, { signal: controller.signal }); if (!response.ok) throw new Error(`HTTP ${response.status}`); const json = await response.json(); setData(json); setError(null); } catch (err) { if (err instanceof Error && err.name !== 'AbortError') { setError(err); } } finally { setLoading(false); } } fetchData(); return () => controller.abort(); }, [url]); return { data, error, loading }; } // Local storage hook function useLocalStorage<T>(key: string, initialValue: T) { const [storedValue, setStoredValue] = useState<T>(() => { try { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch { return initialValue; } }); const setValue = useCallback((value: T | ((val: T) => T)) => { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); window.localStorage.setItem(key, JSON.stringify(valueToStore)); }, [key, storedValue]); return [storedValue, setValue] as const; } // Debounce hook function useDebounce<T>(value: T, delay: number): T { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const timer = setTimeout(() => setDebouncedValue(value), delay); return () => clearTimeout(timer); }, [value, delay]); return debouncedValue; } ``` ### State Management ```tsx // Zustand - simple global state import { create } from 'zustand'; import { persist } from 'zustand/middleware'; interface CartStore { items: CartItem[]; addItem: (item: CartItem) => void; removeItem: (id: string) => void; clearCart: () => void; total: () => number; } const useCartStore = create<CartStore>()( persist( (set, get) => ({ items: [], addItem: (item) => set((state) => ({ items: [...state.items, item] })), removeItem: (id) => set((state) => ({ items: state.items.filter(i => i.id !== id) })), clearCart: () => set({ items: [] }), total: () => get().items.reduce((sum, item) => sum + item.price, 0) }), { name: 'cart-storage' } ) ); // React Query / TanStack Query import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; function useUsers() { return useQuery({ queryKey: ['users'], queryFn: () => api.getUsers(), staleTime: 5 * 60 * 1000, // 5 minutes }); } function useCreateUser() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (newUser: CreateUserInput) => api.createUser(newUser), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['users'] }); }, }); } ``` --- ## Next.js / App Router ### Server Components ```tsx // app/users/page.tsx - Server Component (default) async function UsersPage() { // Direct database access in server component const users = await db.user.findMany(); return ( <div> <h1>Users</h1> <UserList users={users} /> </div> ); } // Client component for interactivity 'use client'; import { useState } from 'react'; function UserList({ users }: { users: User[] }) { const [selected, setSelected] = useState<string | null>(null); return ( <ul> {users.map(user => ( <li key={user.id} onClick={() => setSelected(user.id)} className={selected === user.id ? 'selected' : ''} > {user.name} </li> ))} </ul> ); } ``` ### Server Actions ```tsx // app/actions.ts 'use server'; import { revalidatePath } from 'next/cache'; import { redirect } from 'next/navigation'; export async function createUser(formData: FormData) { const name = formData.get('name') as string; const email = formData.get('email') as string; await db.user.create({ data: { name, email } }); revalidatePath('/users'); redirect('/users'); } // Usage in component function CreateUserForm() { return ( <form action={createUser}> <input name="name" required /> <input name="email" type="email" required /> <button type="submit">Create</button> </form> ); } ``` ### Route Handlers ```tsx // app/api/users/route.ts import { NextRequest, NextResponse } from 'next/server'; export async function GET(request: NextRequest) { const searchParams = request.nextUrl.searchParams; const limit = parseInt(searchParams.get('limit') || '10'); const users = await db.user.findMany({ take: limit }); return NextResponse.json(users); } export async function POST(request: NextRequest) { const body = await request.json(); const user = await db.user.create({ data: body }); return NextResponse.json(user, { status: 201 }); } ``` --- ## CSS & Styling ### Tailwind CSS ```tsx // Component with Tailwind function Card({ title, children }: { title: string; children: React.ReactNode }) { return ( <div className="rounded-lg border border-gray-200 bg-white p-6 shadow-sm hover:shadow-md transition-shadow duration-200 dark:bg-gray-800 dark:border-gray-700"> <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4"> {title} </h2> <div className="text-gray-600 dark:text-gray-300"> {children} </div> </div> ); } // With clsx/cn for conditional classes import { clsx } from 'clsx'; import { twMerge } from 'tailwind-merge'; function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } function Button({ variant = 'primary', size = 'md', className, ...props }: ButtonProps) { return ( <button className={cn( 'inline-flex items-center justify-center rounded-md font-medium', 'focus:outline-none focus:ring-2 focus:ring-offset-2', { 'bg-blue-600 text-white hover:bg-blue-700': variant === 'primary', 'bg-gray-200 text-gray-900 hover:bg-gray-300': variant === 'secondary', 'px-3 py-1.5 text-sm': size === 'sm', 'px-4 py-2 text-base': size === 'md', 'px-6 py-3 text-lg': size === 'lg', }, className )} {...props} /> ); } ``` ### CSS Modules ```tsx // Button.module.css .button { padding: 0.5rem 1rem; border-radius: 0.375rem; font-weight: 500; } .primary { background-color: var(--color-primary); color: white; } .secondary { background-color: var(--color-gray-200); color: var(--color-gray-900); } // Button.tsx import styles from './Button.module.css'; function Button({ variant = 'primary', children }) { return ( <button className={`${styles.button} ${styles[variant]}`}> {children} </button> ); } ``` --- ## Performance Optimization ### Code Splitting ```tsx // Dynamic imports import dynamic from 'next/dynamic'; const HeavyChart = dynamic(() => import('./HeavyChart'), { loading: () => <ChartSkeleton />, ssr: false, // Client-only component }); // React.lazy with Suspense const Dashboard = lazy(() => import('./Dashboard')); function App() { return ( <Suspense fallback={<Loading />}> <Dashboard /> </Suspense> ); } ``` ### Virtualization ```tsx import { useVirtualizer } from '@tanstack/react-virtual'; function VirtualList({ items }: { items: Item[] }) { const parentRef = useRef<HTMLDivElement>(null); const virtualizer = useVirtualizer({ count: items.length, getScrollElement: () => parentRef.current, estimateSize: () => 50, }); return (
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る