cloudflare-api
Hit the Cloudflare REST API directly for operations that wrangler and MCP can't handle well. Bulk DNS, custom hostnames, email routing, cache purge, WAF rules,…
React 19 performance patterns and composition architecture for Vite + Cloudflare projects. 50+ rules ranked by impact — eliminating waterfalls, bundle optimisation, re-render prevention, composition over boolean props, server/client boundaries, and React 19 APIs. Use when
$ npx -y skills add jezweb/claude-skills --skill react-patterns --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/react-patternsContext preview
The summary Claude sees to decide when to auto-load this skill.
React 19 performance patterns and composition architecture for Vite + Cloudflare projects. 50+ rules ranked by impact — eliminating waterfalls, bundle optimisation, re-render prevention, composition over boolean props, server/client boundaries, and React 19 APIs. Use when
name: react-patterns description: "React 19 performance patterns and composition architecture for Vite + Cloudflare projects. 50+ rules ranked by impact — eliminating waterfalls, bundle optimisation, re-render prevention, composition over boolean props, server/client boundaries, and React 19 APIs. Use when writing, reviewing, or refactoring React components. Triggers: 'react patterns', 'react review', 'react performance', 'optimise components', 'react best practices', 'composition patterns', 'why is it slow', 'reduce re-renders', 'fix waterfall'." compatibility: claude-code-only allowed-tools: - Read - Glob - Grep
Performance and composition patterns for React 19 + Vite + Cloudflare Workers projects. Use as a checklist when writing new components, a review guide when auditing existing code, or a refactoring playbook when something feels slow or tangled.
Rules are ranked by impact. Fix CRITICAL issues before touching MEDIUM ones.
Sequential async calls where they could be parallel. The #1 performance killer.
| Pattern | Problem | Fix | |---------|---------|-----| | **Await in sequence** | `const a = await getA(); const b = await getB();` | `const [a, b] = await Promise.all([getA(), getB()]);` | | **Fetch in child** | Parent renders, then child fetches, then grandchild fetches | Hoist fetches to the highest common ancestor, pass data down | | **Suspense cascade** | Multiple Suspense boundaries that resolve sequentially | One Suspense boundary wrapping all async siblings | | **Await before branch** | `const data = await fetch(); if (condition) { use(data); }` | Move await inside the branch — don't fetch what you might not use | | **Import then render** | `const Component = await import('./Heavy'); return <Component />` | Use `React.lazy()` + `<Suspense>` — renders fallback instantly |
**How to find them**: Search for `await` in components. Each `await` is a potential waterfall. If two awaits are independent, they should be parallel.
Every KB the user downloads is a KB they wait for.
| Pattern | Problem | Fix | |---------|---------|-----| | **Barrel imports** | `import { Button } from '@/components'` pulls the entire barrel file | `import { Button } from '@/components/ui/button'` — direct import | | **No code splitting** | Heavy component loaded on every page | `React.lazy(() => import('./HeavyComponent'))` + `<Suspense>` | | **Third-party at load** | Analytics/tracking loaded before the app renders | Load after hydration: `useEffect(() => { import('./analytics') }, [])` | | **Full library import** | `import _ from 'lodash'` (70KB) | `import debounce from 'lodash/debounce'` (1KB) | | **Lucide tree-shaking** | `import * as Icons from 'lucide-react'` (all icons) | Explicit map: `import { Home, Settings } from 'lucide-react'` | | **Duplicate React** | Library bundles its own React → "Cannot read properties of null" | `resolve.dedupe: ['react', 'react-dom']` in vite.config.ts |
**How to find them**: `npx vite-bundle-visualizer` — shows what's in your bundle.
How you structure components matters more than how you optimise them.
| Pattern | Problem | Fix | |---------|---------|-----| | **Boolean prop explosion** | `<Card isCompact isClickable showBorder hasIcon isLoading>` | Explicit variants: `<CompactCard>`, `<ClickableCard>` | | **Compound components** | Complex component with 15 props | Split into `<Dialog>`, `<Dialog.Trigger>`, `<Dialog.Content>` with shared context | | **renderX props** | `<Layout renderSidebar={...} renderHeader={...} renderFooter={...}>` | Use children + named slots: `<Layout><Sidebar /><Header /></Layout>` | | **Lift state** | Sibling components can't share state | Move state to parent or context provider | | **Provider implementation** | Consumer code knows about state management internals | Provider exposes interface `{ state, actions, meta }` — implementation hidden | | **Inline components** | `function Parent() { function Child() { ... } return <Child /> }` | Define Child outside Parent — inline components remount on every render |
**The test**: If a component has more than 5 boolean props, it needs composition, not more props.
Not all re-renders are bad. Only fix re-renders that cause visible jank or wasted computation.
| Pattern | Problem | Fix | |---------|---------|-----| | **Default object/array props** | `function Foo({ items = [] })` → new array ref every render | Hoist: `const DEFAULT = []; function Foo({ items = DEFAULT })` | | **Derived state in effect** | `useEffect(() => setFiltered(items.filter(...)), [items])` | Derive during render: `const filtered = useMemo(() => items.filter(...), [items])` | | **Object dependency** | `useEffect(() => {...}, [config])` fires every render if config is `{}` | Use primitive deps: `useEffect(() => {...}, [config.id, config.type])` | | **Subscribe to unused state** | Component reads `{ user, theme, settings }` but only uses `user` | Split context or use selector: `useSyncExternalStore` | | **State for transient values** | `const [mouseX, setMouseX] = useState(0)` on mousemove | Use `useRef` for values that change frequently but don't need re-render | | **Inline callback props** | `<Button onClick={() => doThing(id)} />` — new function every render | `useCallback` or functional setState: `<Button onClick={handleClick} />` |
**How to find them**: React DevTools Profiler → "Why did this render?" or `<React.StrictMode>` double-renders in dev.
Patterns that changed or are new in React 19.
| Pattern | Old (React 18) | N
Production workflow skills for Claude Code. Each skill guides Claude through a recipe to produce tangible output — scaffolded projects, generated assets, professional documents, deployed services. Ten plugins of practical, production-oriented skills.
Repo: jezweb/claude-skills
Hit the Cloudflare REST API directly for operations that wrangler and MCP can't handle well. Bulk DNS, custom hostnames, email routing, cache purge, WAF rules,…
Scaffold and deploy Cloudflare Workers with Hono routing, Vite plugin, and Static Assets. Describe project, scaffold structure, configure bindings, deploy. Use…
Generate Drizzle ORM schemas for Cloudflare D1 databases with correct D1-specific patterns. Produces schema files, migration commands, type exports, and…
Cloudflare D1 migration workflow: generate with Drizzle, inspect SQL for gotchas, apply to local and remote, fix stuck migrations, handle partial failures. Use…
Generate database seed scripts with realistic sample data. Reads Drizzle schemas or SQL migrations, respects foreign key ordering, produces idempotent…
Scaffold Hono API routes for Cloudflare Workers. Produces route files, middleware, typed bindings, Zod validation, error handling, and API_ENDPOINTS.md…