React Operations

SkillAI & models

React development patterns, hooks, state management, Server Components, and performance optimization. Use for: react, hooks, useState, useEffect, jsx, tsx, next.js, nextjs, app router, server components, RSC, zustand, react query, component patterns, react testing library, error boundary, suspense, react 19.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the React Operations skill

What this skill tells your AI

The instructions your AI receives, as published by 0xdarkmatter/claude-mods in skills/react-ops/SKILL.md and read by ahel’s review.

Comprehensive React skill covering hooks, component architecture, state management, Server Components, and performance optimization.

React 19 ecosystem facts verified as of 2026-07.

Hook Selection Decision Tree

What problem are you solving?
│
├─ Storing UI state that triggers re-renders
│  ├─ Simple value (string, number, boolean)
│  │  └─ useState
│  ├─ Complex state with multiple sub-values and logic
│  │  └─ useReducer (actions + reducer = predictable transitions)
│  └─ Derived from existing state
│     └─ Calculate inline or useMemo — not useState
│
├─ Referencing a value WITHOUT triggering re-render
│  ├─ DOM element reference
│  │  └─ useRef<HTMLElement>(null) + ref={ref}
│  └─ Mutable value (timer ID, previous value, counter)
│     └─ useRef (mutate ref.current directly)
│
├─ Running a side effect
│  ├─ After every render (or specific deps)
│  │  ├─ Needs cleanup (subscription, timer, abort)
│  │  │  └─ useEffect with return cleanup function
│  │  └─ No cleanup (logging, analytics)
│  │     └─ useEffect with empty or dep array
│  ├─ Before browser paint (DOM mutation, animation)
│  │  └─ useLayoutEffect
│  └─ Triggered by user action (not render)
│     └─ Call it directly in the event handler — not useEffect
│
├─ Caching an expensive computation
│  └─ useMemo(() => expensiveCalc(a, b), [a, b])
│
├─ Stable callback reference for child props / event handlers
│  └─ useCallback(() => doThing(dep), [dep])
│
├─ Reading shared context value
│  └─ useContext(MyContext)
│
├─ Generating stable unique ID (forms, aria)
│  └─ useId()
│
├─ Syncing external store (Redux, Zustand internals)
│  └─ useSyncExternalStore(subscribe, getSnapshot)
│
└─ React 19+
   ├─ Await a promise or read context
   │  └─ use(promise | context)
   ├─ Form submit state (pending, data, action)
   │  └─ useFormStatus / useActionState
   └─ Optimistic UI before server response
      └─ useOptimistic(state, updateFn)

Component Pattern Decision Tree

What's your composition challenge?
│
├─ Group of related components sharing implicit state
│  (Tabs, Accordion, Select, Menu)
│  └─ Compound Components with Context
│     Parent provides state via Context
│     Children consume via useContext
│
├─ Consumer needs to control rendering output
│  └─ Render Props: children(props) or render={fn}
│     Good for: headless UI, flexible layouts
│
├─ Apply cross-cutting concerns (auth, logging, theming)
│  to multiple components
│  └─ Higher-Order Components (HOC)
│     Wrap with withAuth(Component) or withLogging(Component)
│     Prefer custom hooks for pure logic
│
├─ Encapsulate reusable stateful logic
│  └─ Custom Hook — always prefer over HOC when possible
│     Composable, testable, no wrapper hell
│
├─ Need imperative control from parent (focus, scroll, reset)
│  └─ forwardRef + useImperativeHandle
│
├─ Render content outside DOM hierarchy (modal, tooltip, toast)
│  └─ Portal: createPortal(content, document.body)
│
├─ Accept arbitrary children/slots without prop drilling
│  └─ Slot pattern via children, or named props (header, footer)
│
└─ Polymorphic rendering (button that renders as <a> or div)
   └─ as prop pattern with TypeScript generics

State Management Decision Tree

Where does this state live and who owns it?
│
├─ Only one component needs it
│  └─ useState or useReducer (local state)
│
├─ A few nearby components need it
│  └─ Lift state to nearest common ancestor + prop drilling
│     (2-3 levels is fine)
│
├─ Many components need it, rarely changes
│  (theme, locale, auth user)
│  └─ React Context API
│     Split contexts by update frequency
│     Avoid single giant context
│
├─ Global client state, changes often
│  (shopping cart, UI preferences, navigation)
│  ├─ Simple/small app → Zustand (minimal boilerplate)
│  ├─ Atomic updates, React Suspense integration → Jotai
│  └─ Large team, time-travel debugging, complex logic → Redux Toolkit
│
├─ Server state (remote data, cache, sync)
│  (API data, database queries)
│  └─ TanStack Query (React Query)
│     Handles: caching, background refetch, loading/error
│     Don't use useState + useEffect for server data
│
└─ Form state
   └─ React Hook Form + Zod validation
      (controlled inputs are fine for simple forms)

React 19 Quick Reference

FeatureAPIPurpose
use() hookuse(promise) / use(context)Await promises in render, read context conditionally
Actionsasync function action(formData)Async transitions with built-in pending state
useActionStateuseActionState(action, initialState)Action result + pending state
useFormStatususeFormStatus()Pending/data/method inside form
useOptimisticuseOptimistic(state, updateFn)Optimistic UI before server response
React CompilerAutomatic memoizationReplaces most memo, useMemo, useCallback
ref as prop<Input ref={ref}>No more forwardRef wrapper needed
<Context> as provider<MyContext value={val}>No more <MyContext.Provider>
// React 19: use() for data fetching in Server Components
import { use } from 'react';

function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
  const user = use(userPromise); // suspends until resolved
  return <h1>{user.name}</h1>;
}

// React 19: useActionState
import { useActionState } from 'react';

function ContactForm() {
  const [state, action, isPending] = useActionState(
    async (prevState: State, formData: FormData) => {
      const result = await submitContact(formData);
      return result;
    },
    { error: null }
  );

  return (
    <form action={action}>
      <input name="email" type="email" />
      <button disabled={isPending}>
        {isPending ? 'Sending...' : 'Send'}
      </button>
      {state.error && <p>{state.error}</p>}
    </form>
  );
}

Server vs Client Components

Does this component need...?
│
├─ useState, useReducer, useContext
│  └─ Client Component ('use client')
│
├─ useEffect, useLayoutEffect
│  └─ Client Component ('use client')
│
├─ Browser APIs (window, document, localStorage)
│  └─ Client Component ('use client')
│
├─ Event handlers (onClick, onChange, onSubmit)
│  └─ Client Component ('use client')
│
├─ Third-party libraries that use hooks/browser APIs
│  └─ Client Component ('use client')
│
├─ Direct database/file system access
│  └─ Server Component (default, no directive)
│
├─ Access to env vars (server-only secrets)
│  └─ Server Component
│
├─ Large dependencies you want to keep off the client bundle
│  └─ Server Component
│
└─ async/await at the top level
   └─ Server Component

Client boundary rules:

  • 'use client' marks a boundary — everything imported below it becomes client JS
  • Server Components can import Client Components (they pass as props/children)
  • Client Components CANNOT import Server Components directly
  • Pass Server Component output as children prop to Client Components
  • Server data → Client: pass as serializable props only (no functions, classes, DOM nodes)

Performance Checklist

TechniqueWhen to UseWhen NOT to Use
React.memoComponent re-renders often with same propsNearly everything — adds comparison overhead
useMemoExpensive calculation (>1ms), stable dep arrayPrimitive values, simple expressions
useCallbackCallback passed to memoized child or in dep arrayInline handlers on DOM elements
React.lazy + SuspenseLarge components not needed on initial loadSmall components, SSR-critical content
useTransitionNon-urgent state updates (filtering, sorting)Time-sensitive UI (typing, hover)
useDeferredValueDerived expensive render from fast-changing valueSame as above
VirtualizationLists >100 itemsSmall lists — overhead not worth it
React Compiler (v19)Automatic — replaces most manual memoizationOpt-out with "use no memo" if needed

Common Gotchas

GotchaWhy It HappensFix
Stale closure in useEffectCallback captures old state/prop at definition timeAdd value to dep array, or use functional update setState(prev => ...)
Missing useEffect dependencyLinter disabled or ignored, stale data shownNever disable exhaustive-deps; use useCallback to stabilize functions
Index as list keyKeys change on reorder/insert, causing wrong component identityUse stable unique ID from data (item.id)
Hydration mismatchServer HTML doesn't match first client renderAvoid typeof window, random values, or dates in render; use useEffect for client-only content
Unnecessary re-renders from contextAll consumers re-render when any context value changesSplit context by concern; memoize context value with useMemo
useEffect for derived stateState derived from another state causes extra render cycleCompute derived value during render inline or with useMemo
Missing cleanup in useEffectMemory leaks from subscriptions, timers, fetch requestsAlways return cleanup function; use AbortController for fetch
Strict Mode double invocationEffects run twice in dev to catch bugsDesign effects to be idempotent; cleanup must fully reverse effect
Controlled/uncontrolled switchvalue prop toggling between defined and undefinedAlways provide defined value or always use defaultValue; never both
Object/array in dep arrayNew reference every render triggers effect repeatedlyMemoize with useMemo; use primitive values in deps where possible
Async function directly in useEffectuseEffect(() => async () => {}) returns a Promise, not cleanupWrap: useEffect(() => { async function run() {...}; run(); }, [])

Reference Files

FileWhen to Load
./references/hooks-patterns.mdDeep hook usage: custom hooks, React 19 hooks, useEffect patterns, hook composition
./references/component-architecture.mdCompound components, HOC, render props, portals, forwardRef, polymorphic components
./references/state-management.mdContext API, Zustand, Jotai, Redux Toolkit, TanStack Query, React Hook Form
./references/server-components.mdRSC architecture, Server Actions, Next.js App Router, caching, streaming, metadata
./references/performance.mdReact.memo, code splitting, virtualization, React Compiler, Web Vitals, profiling
./references/testing.mdRTL queries, user-event, MSW, renderHook, Vitest setup, accessibility testing

Staleness Verifier

This skill encodes fast-moving facts (the React 19 API surface, the ecosystem package stack). scripts/check-react-facts.py guards them against silent drift — internal consistency in PR CI, live major-version drift in the scheduled freshness job:

# Structural (PR CI, no network): every catalogued package + React 19 gate is
# still named in this skill's prose, and the currency note still carries a year.
python3 skills/react-ops/scripts/check-react-facts.py --offline        # exit 0 consistent, 10 drift

# Live (weekly freshness job, never blocks a PR): is any documented major
# now behind npm's latest dist-tag?
python3 skills/react-ops/scripts/check-react-facts.py --live           # exit 10 a major moved ahead, 7 npm unreachable

The canonical fact list lives in assets/react-facts.json; when you add or drop a recommendation or the prose stops naming one, update it to match or --offline fails CI.

See Also

SkillWhen to Combine
typescript-opsTypeScript generics with React props, discriminated unions for state machines, utility types
testing-opsTest strategy, mocking patterns, CI integration, snapshot vs behavioral tests
tailwind-opsCSS-in-JS alternatives, responsive design with Tailwind in React components
javascript-opsAsync patterns, Promises, generators, module system fundamentals

Signals

GitHub stars
36
Forks
5
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
react-ops
Source
github.com/0xdarkmatter/claude-mods