Back to skills
extension
Category: Development & EngineeringNo API key required

lang-react

Build React SPAs where components are declarative UI consuming external state (Zustand/XState/TanStack Query). Logic lives in stores, not components.

personAuthor: jakexiaohubgithub

React Expert

Core Philosophy

Components consume external state, contain no logic:

  • External hooks at top (Zustand, XState, TanStack Query)
  • No useState/useReducer/useEffect for complex logic
  • Inline actions unless repeated 2+ times
  • Test stores/machines (unit tests), not components (E2E only)

State Management Stack

| State Type | Solution | | --------------------- | ---------------------------- | | Remote (REST) | TanStack Query | | Remote (GraphQL) | Apollo Client | | Application state | Zustand | | Complex machines | XState | | Local UI state | useState (rare, last resort) |

Component Pattern

// ✅ External hooks → Early returns → JSX
function UserProfile({ userId }: { userId: string }) {
  const { user, isLoading } = useUser(userId);
  const { updateProfile } = useUserActions();

  if (isLoading) return <Spinner />;

  return (
    <div>
      <h1>{user.name}</h1>
      <button onClick={() => updateProfile({ email: 'new@example.com' })}>
        Update
      </button>
    </div>
  );
}

Testing: Stores, Not Components

| What | Tool | Why | | --------------- | ---------- | ------------------------- | | Zustand stores | Vitest | Test without React | | XState machines | Vitest | Deterministic transitions | | Critical flows | Playwright | Real browser | | Components | Never | Logic should be in stores |

// Test store directly
const { login } = useAuthStore.getState();
await login({ email: "test@example.com", password: "pass" });
expect(useAuthStore.getState().user).toBeDefined();

Unique Patterns

Prop Ordering: Simple → Complex

<Table
  data={items}
  loading={isLoading}
  sortable
  onSort={handleSort}
  renderRow={(item) => <Row>{item.name}</Row>}
/>

Inline Props for Type Inference

// ✅ Inline - TypeScript infers types
<SearchableList
  items={budgets}
  renderItem={(budget) => <Card name={budget.name} />}
/>;

// ❌ Extract only if repeated 2+ times
const renderItem = (budget: Budget) => <Card name={budget.name} />;

Pattern Matching for Variants

import { match } from "ts-pattern";

{
  match(state)
    .with({ _tag: "loading" }, () => <Spinner />)
    .with({ _tag: "success" }, (s) => <Data value={s.data} />)
    .exhaustive();
}

Performance: Profile First

| Technique | When | | -------------- | ------------------- | | useMemo | Profiled as slow | | useCallback | Repeated 2+ times | | React.memo | Props rarely change | | Code splitting | Route-level |

Styled-Components: Consolidate with CSS Selectors

// ✅ Single component with CSS selectors
const Table = styled.table`
  thead {
    background: ${(p) => p.theme.colors.header};
  }
  tbody tr:hover {
    background: ${(p) => p.theme.colors.hover};
  }
  td {
    padding: ${(p) => p.theme.space.md};
  }
`;

// ❌ Separate components for each element
const TableHeader = styled.thead`...`;
const TableRow = styled.tr`...`;
const TableCell = styled.td`...`;

Version 1.0.1