Skip to content

@tank/react

2.3.0
Skill

Description

React patterns for production apps. Component composition (compound, polymorphic, slots), hooks, state architecture, performance, React 19 (use, Actions, useActionState, useFormStatus, ref as prop), React Compiler auto-memoization, Vite-era tooling, TanStack Query server state, Suspense-first data loading, and linting with React Doctor..

Download
Verified
tank install @tank/react

React

Core Philosophy

  • Composition over configuration: shape APIs with children, slots, and small props.
  • Colocation principle: keep state, view, and data fetching near the consumer.
  • Derive, don't sync: compute from source of truth, avoid mirror state.
  • Make invalid states unrepresentable: model state transitions explicitly.
  • Optimize for change: prefer patterns that localize edits.
  • Keep effects reactive: side effects follow data, not events.
  • Name state by intent, not by UI widget.

Component Decision Tree

When you needUseWhyNotes
Static UI with simple propsSimple componentLowest overheadKeep props shallow
Shared state across related piecesCompound componentImplicit coordinationUse context + slots
Element-agnostic stylingPolymorphic (as prop)Unified API across elementsType as for safety
Behavior injection into layoutRender propFlexible controlPrefer stable function identity
Wrap a 3rd-party APIHOCEncapsulate wiringAvoid for new component APIs
Reuse logic without UICustom hookShare behaviorReturn data + actions

State Management Decision Tree

SituationUseRationaleTradeoffs
Single field or UI toggleuseStateDirect, localAvoid derived duplicates
Multi-step workflowuseReducerExplicit transitionsSlightly more boilerplate
Shared local UI stateContextAvoid prop drillingSplit by concern
Cross-route app stateExternal storeCentralized accessUse selectors
Server data cacheTanStack QueryCache + syncLearn invalidation

Hooks Rules of Thumb

  • Start with state local; lift only when 2+ siblings depend on it.
  • Prefer useReducer when updates depend on the previous state in many places.
  • Put async data in a server-state tool; don't mirror it in useState.
  • Make effects about synchronization, not computation.
  • Stabilize callbacks only when you pass them to memoized children.
  • Store derived values with useMemo only when recomputation is expensive.
  • Avoid useEffect for DOM reads; reach for refs and layout effects intentionally.
  • If a hook returns both data and actions, keep the action names stable.
  • Minimize hook parameters; prefer passing config objects.

React 19 Features Quick Reference

FeatureWhat it enablesWhen to usePitfall
use()Read promises/context in renderServer and client data boundariesRequires Suspense
ActionsAsync mutations with form integrationForm submissionsAvoid manual loading flags
useOptimisticInstant UI while awaiting serverMutations with predictable rollbackEnsure reconciliation
useActionStateForm action result + pending flagServer/client form actionsReplaces deprecated useFormState
useFormStatusRead parent form pending stateSubmit buttons, progress indicatorsMust be child of <form>
ref as propPass refs without forwardRefAny component exposing DOMDrop forwardRef boilerplate
Server ComponentsZero-bundle UI on serverRead-only, data-heavy viewsRequires boundary discipline
Context as provider<Ctx> replaces <Ctx.Provider>All context usageDrop .Provider suffix

Modern React Stack (2026)

LayerToolWhyNote
BundlerViteFast HMR, ESM-nativeplugin-react-swc for speed
MemoizationReact CompilerAuto-memoizes pure rendersRemove manual memo when adopted
Server stateTanStack QueryCache, invalidation, optimistic UIReplaces useEffect fetch patterns
Data loadingSuspense + use()Declarative async boundariesBoundaries at latency points
Client stateuseState / useReducerLocal-first, lift only when neededExternal stores for cross-route
RoutingTanStack Router / React RouterType-safe, loaders prevent waterfallsFile-based or config-based

-> See references/modern-react-2026.md for setup guides and detailed patterns.

Anti-Patterns

Don'tDo InsteadWhy
Prop drill through 4+ layersIntroduce Context boundaryReduce wiring churn
Copy props into stateDerive in renderAvoid divergence
useEffect to compute derived valuesuseMemo or inlineKeep data flow explicit
Store server data in useStateUse query cacheBuilt-in invalidation
Overuse React.memoMemoize only hotspotsExtra work otherwise
Inline object props every renderMemoize or hoistStabilize referential equality
One global Context for everythingSplit by domainReduce rerenders
Event handlers with stale stateUse functional updatesAvoid stale closure bugs
Keys from array indexStable domain IDsPreserve item identity
Wrap in forwardRef (React 19+)Pass ref as regular propLess boilerplate

Component API Checklist

  • Expose the minimum props needed to express intent.
  • Prefer boolean props for mode switches; prefer enums for variants.
  • Use children for structure and provide slots for customization.
  • Keep side-effecting props explicit (onOpen, onClose, onSubmit).
  • Return primitive data from hooks, not JSX.
  • If a prop can be derived, remove it from the public API.
  • Keep controlled and uncontrolled modes separate and obvious.
  • Document default behavior with tests.

Effect Design Checklist

  • Identify the external system being synchronized.
  • Keep the dependency list aligned with the system inputs.
  • Use AbortController for fetch cancellation.
  • Prefer useLayoutEffect only for layout reads or measurement.
  • Cleanup always mirrors setup; avoid conditional cleanup.
  • Avoid setState in effects when value can be derived.
  • Never wire effects to user events; use event handlers.
  • Promote repeated effect patterns into a custom hook.

Suspense and Data Boundaries

  • Add Suspense at product-level latency points, not every component.
  • Keep fallback UI representative of the final layout.
  • Isolate error boundaries per feature area.
  • Avoid shared mutable state across server and client components.
  • Use data loaders at route boundaries to avoid waterfalls.
  • Prefer streaming for long-tail data, keep critical path small.
  • Avoid hiding errors by catching promises without rendering.

Testing Heuristics

  • Test the user-visible output, not internal state.
  • Prefer React Testing Library queries that match user intent.
  • Avoid snapshot tests for dynamic content; assert specific UI.
  • Use MSW or a query cache to model server responses.
  • Separate unit tests for hooks from integration tests for screens.
  • Assert optimistic updates and rollback behavior explicitly.
  • Keep test data realistic to catch rendering edge cases.
  • When in doubt, test the boundary between components.

TypeScript Integration

  • Model props with discriminated unions for variant-driven UIs.
  • Type children explicitly when slots are required.
  • Use ComponentPropsWithoutRef<"button"> for pass-through props.
  • Prefer satisfies to keep config objects narrow.
  • Keep hooks generic only when the type pays for itself.
  • Treat as polymorphism as part of the public API contract.

Operational Workflow

  • Start by modeling state transitions in a reducer or state chart.
  • Build the smallest component tree that expresses the intent.
  • Add composition points only after usage shows friction.
  • Introduce Suspense and streaming after data paths are stable.
  • Profile before memoization to avoid premature tuning.
  • Document invariants with tests instead of comments.

Performance Posture

  • Prefer fewer renders over cheaper renders when possible.
  • Avoid re-render cascades by splitting context providers.
  • Use virtualization when list size > 200 or rendering cost is high.
  • Treat memo and useCallback as opt-in tools, not defaults.
  • When React Compiler is active, remove redundant manual memoization.
  • Split bundles by route first, then by heavy widget.
  • Inspect bundle output to validate tree-shaking.
  • Defer non-critical work with useTransition or Actions.
  • Use stable keys and stable item identity for lists.

Migration Notes

  • Prefer incremental refactors; wrap new components under old API.
  • Introduce adapters for legacy props; deprecate in types.
  • Use codemods for prop renames and hook replacements.
  • Keep fallback UI identical during data-layer changes.
  • Add feature flags for high-risk UI rewrites.
  • Gate server component adoption per route.
  • Keep a clear rollback path for Actions adoption.
  • Remove dead code after two releases.

Refactor Triggers

  • Prop lists exceed 8-10 items or include derived values.
  • Effects contain more than one external resource.
  • A component has more than 2 responsibilities.
  • A hook has side effects and state but no cleanup.
  • Re-render time dominates in the profiler.
  • Teams repeatedly add exceptions to the API.

Linting with React Doctor

React Doctor scans for anti-patterns and outputs a 0-100 health score. Run npx -y react-doctor@latest . to scan. Use --diff main for CI, --fix to auto-fix, --score for CI-friendly numeric output. -> See references/react-doctor.md for the full rule reference, CI integration, and configuration.

Reference Index

FileContents
references/component-patterns.mdCompound, polymorphic, slots, render props, controlled/uncontrolled
references/hooks-and-state.mdCustom hooks, useReducer patterns, effects, React 19 hooks
references/performance.mdMemo, code splitting, virtualization, React Compiler, profiling
references/modern-react-2026.mdVite setup, React Compiler adoption, TanStack Query, React 19 API
references/react-doctor.mdFull rule reference, CI setup, configuration, programmatic API

Command Palette

Search packages, docs, and navigate Tank