Skip to content

/ia-react-frontend

React architecture patterns, TypeScript, Next.js, hooks, and testing. Use when working with React component structure, state management, Next.js routing, Vitest, React Testing Library, or reviewing React code. For visual design and aesthetic direction, use frontend-design

From plugin
2831 skills12 commands
shell
$ npx -y skills add iliaal/whetstone --skill ia-react-frontend --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/ia-react-frontend
How auto-invocation works

Context preview

The summary Claude sees to decide when to auto-load this skill.

React architecture patterns, TypeScript, Next.js, hooks, and testing. Use when working with React component structure, state management, Next.js routing, Vitest, React Testing Library, or reviewing React code. For visual design and aesthetic direction, use frontend-design

SKILL.md

ia-react-frontend.SKILL.md
name: ia-react-frontend
class: language
description: >-
  React architecture patterns, TypeScript, Next.js, hooks, and testing. Use when
  working with React component structure, state management, Next.js routing,
  Vitest, React Testing Library, or reviewing React code. For visual design and
  aesthetic direction, use frontend-design instead.
paths: "**/*.tsx,**/*.jsx"

React Frontend

**Verify before implementing**: For App Router patterns, React 19 APIs, or version-specific behavior, look up current docs (Context7 `query-docs` if available, else the framework's official docs via web search) before writing code. Training data may lag current releases.

Component TypeScript

  • Extend native elements with `ComponentPropsWithoutRef<'button'>`, add custom props via intersection
  • Use `React.ReactNode` for children, `React.ReactElement` for single element, render prop `(data: T) => ReactNode`
  • Discriminated unions for variant props -- TypeScript narrows automatically in branches
  • Generic components: `<T>` with `keyof T` for column keys, `T extends { id: string }` for constraints
  • Event types: `React.MouseEvent<HTMLButtonElement>`, `FormEvent<HTMLFormElement>`, `ChangeEvent<HTMLInputElement>`
  • `as const` for custom hook tuple returns
  • `useRef<HTMLInputElement>(null)` for DOM (use `?.`), `useRef<number>(0)` for mutable values
  • Explicit `useState<User | null>(null)` for unions/null
  • useReducer actions as discriminated unions: `{ type: 'set'; payload: number } | { type: 'reset' }`
  • useContext null guard: throw in custom `useX()` hook if context is null

Effects Decision Tree

Effects are escape hatches -- most logic should NOT use effects.

| Need | Solution | |------|----------| | Derived value from props/state | Calculate during render (useMemo if expensive) | | Reset state on prop change | `key` prop on component | | Respond to user event | Event handler | | Notify parent of state change | Call onChange in event handler, or fully controlled component | | Chain of state updates | Calculate all next state in one event handler | | Sync with external system | Effect with cleanup |

**Effect rules:**

  • Never suppress the linter -- fix the code instead
  • Use updater functions (`setItems(prev => [...prev, item])`) to remove state dependencies
  • Move objects/functions inside effects to stabilize dependencies
  • `useEffectEvent` for non-reactive values (e.g., theme in a connection effect)
  • Always return cleanup for subscriptions, connections, listeners
  • Data fetching cancellation (pick by situation): `AbortController` for fetch; `ignore` flag for non-cancellable promises; React Query handles both automatically

Concurrency & Race Classes

Five race classes survive type-checking and unit tests -- hunt each one during review (cleanup/cancellation mechanics: Effect rules above):

| Class | Production signal | Fix | |-------|-------------------|-----| | Lifecycle cleanup gap | "state update on unmounted component" warnings, leaks under rapid navigation | Return cleanup from every effect that registers a listener/timer/observer | | Remount-timing mistake | Async callback mutates state/DOM after route change/unmount (`fetch().then(setData)` resolves post-navigation) | Cancel per the cancellation hierarchy | | Boolean-as-state for non-binary UI | Contradictory combos (`isLoading: true, error: Error`) | State constant (`'idle' \| 'loading' \| 'success' \| 'error'`) + transition function; invalid states unreachable | | Stale promise/timer, no cancel path | Promise chain or `setTimeout` holds `setState` after the component moved on | Bind every async op to a cancel mechanism; test the cleanup path | | Per-element handlers on large lists | N closures/subscriptions per row, stale-closure bugs on rapid re-renders | Delegate: one parent handler + `event.target.closest(...)` when >~50 items or frequent updates |

State Management

Local UI state       → useState, useReducer
Shared client state  → Zustand (simple) | Redux Toolkit (complex)
Atomic/granular      → Jotai
Server/remote data   → React Query (TanStack Query)
URL state            → nuqs, router search params
Form state           → React Hook Form

**Key patterns:**

  • Zustand: `create<State>()(devtools(persist((set) => ({...}))))` -- use slices for scale, selective subscriptions to prevent re-renders
  • React Query: query keys factory (`['users', 'detail', id] as const`), `staleTime`/`gcTime`, optimistic updates with `onMutate`/`onError` rollback
  • Never duplicate server data (React Query) in a client store (Zustand)
  • Colocate state close to where it's used

Performance

**Critical -- eliminate waterfalls:**

  • `Promise.all()` for independent async operations
  • Move `await` into branches where actually needed
  • Suspense boundaries to stream slow content

**Critical -- bundle size:**

  • Import directly from modules, avoid barrel files (`index.ts` re-exports)
  • `next/dynamic` or `React.lazy()` for heavy components
  • Defer third-party scripts (analytics, logging) until after hydration
  • Preload on hover/focus for perceived speed
  • `content-visibility: auto` + `contain-intrinsic-size` on long lists -- skips off-screen layout/paint

**Re-render optimization:**

  • Derive state during render, not in effects
  • Subscribe to derived booleans, not raw objects (`state.items.length > 0` not `state.items`)
  • Functional setState for stable callbacks: `setCount(c => c + 1)`
  • Lazy state init: `useState(() => expensiveComputation())`
  • `useTransition` for non-urgent updates (search filtering)
  • `useDeferredValue` for expensive derived UI
  • Don't subscribe to searchParams/state read only in callbacks -- read on demand
  • Use ternary (`condition ? <A /> : <B />`), not `&&` for conditionals
  • `React.memo` only for expensive subtrees with stable props
  • Hoist static JSX outside components

**React Compiler** (React 19): auto-memoizes -- write idiomatic React, remove manual `useMemo`/`useCallback`/`memo`. Enable via `reactCompiler: true` in

Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withwhetstone

A Claude Code plugin that makes AI coding agents follow engineering discipline. Plan before coding. Verify before claiming done. Find root cause before patching. Review before merge. Skills activate based on file type and task signals, not manual toggling.

Get the whole plugin, auto-invoked
Stats
28
Stars
0
Views
2
Forks
Active
Maintenance
Python
Language
MIT
License
4d ago
Last commit
5mo ago
Created

Repo: iliaal/whetstone

Other skills on whetstone.