Loading...
Loading...
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'.
npx skill4agent add jezweb/claude-skills react-patterns| Pattern | Problem | Fix |
|---|---|---|
| Await in sequence | | |
| 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 | | Move await inside the branch — don't fetch what you might not use |
| Import then render | | Use |
awaitawait| Pattern | Problem | Fix |
|---|---|---|
| Barrel imports | | |
| No code splitting | Heavy component loaded on every page | |
| Third-party at load | Analytics/tracking loaded before the app renders | Load after hydration: |
| Full library import | | |
| Lucide tree-shaking | | Explicit map: |
| Duplicate React | Library bundles its own React → "Cannot read properties of null" | |
npx vite-bundle-visualizer| Pattern | Problem | Fix |
|---|---|---|
| Boolean prop explosion | | Explicit variants: |
| Compound components | Complex component with 15 props | Split into |
| renderX props | | Use children + named slots: |
| 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 |
| Inline components | | Define Child outside Parent — inline components remount on every render |
| Pattern | Problem | Fix |
|---|---|---|
| Default object/array props | | Hoist: |
| Derived state in effect | | Derive during render: |
| Object dependency | | Use primitive deps: |
| Subscribe to unused state | Component reads | Split context or use selector: |
| State for transient values | | Use |
| Inline callback props | | |
<React.StrictMode>| Pattern | Old (React 18) | New (React 19) |
|---|---|---|
| Form state | | |
| Ref forwarding | | |
| Context | | |
| Pending UI | Manual loading state | |
| Route-level lazy | Works with | Still true — |
| Optimistic updates | Manual state management | |
| Metadata | Helmet or manual | |
| Pattern | Problem | Fix |
|---|---|---|
| Layout shift on load | Content jumps when async data arrives | Skeleton screens matching final layout dimensions |
| Animate SVG directly | Janky SVG animation | Wrap in |
| Large list rendering | 1000+ items in a table/list | |
| content-visibility | Long scrollable content renders everything upfront | |
| Conditional render with && | | Use ternary: |
| Pattern | Problem | Fix |
|---|---|---|
| No deduplication | Same data fetched by 3 components | TanStack Query or SWR — automatic dedup + caching |
| Fetch on mount | | TanStack Query: |
| No optimistic update | User clicks save, waits 2 seconds, then sees change | |
| Stale closure in interval | | |
| Polling without cleanup | | Return cleanup: |
| Pattern | Problem | Fix |
|---|---|---|
| Undefined — only works in Vite-processed files | Use |
| React duplicate instance | Library bundles its own React | |
| Radix Select empty string | | Use sentinel: |
| React Hook Form null | | Spread manually: |
| Env vars at edge | | Use |
/react-patterns [file or component path]file:line — [rule] description of issue