---
name: programming-in-react
description: Use when writing or modifying React components, planning React features, or working with .jsx/.tsx files - provides modern React patterns with TypeScript, hooks usage, component composition, and common pitfalls to avoid
user-invocable: false
---
# Programming in React
## Overview
Modern React development using functional components, hooks, and TypeScript. This skill guides you through React workflows from component creation to testing.
**Core principle:** Components are functions that return UI. State and effects are managed through hooks. Composition over inheritance always.
**REQUIRED SUB-SKILL:** Use ed3d-house-style:howto-code-in-typescript for general TypeScript patterns. This skill covers React-specific TypeScript usage only.
## When to Use
- Creating or modifying React components
- Working with React hooks (useState, useEffect, custom hooks)
- Planning React features or UI work
- Debugging React-specific issues (hooks errors, render problems)
- When you see .jsx or .tsx files
## Workflow: Creating Components
**Functional components only.** Use `interface` for props, avoid `React.FC`:
```typescript
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean;
}
export function Button({ label, onClick, disabled }: ButtonProps) {
return ;
}
```
**Event typing:** `React.MouseEvent`, `React.ChangeEvent`. Children: `React.ReactNode`.
## Workflow: Managing State
**useState for simple state:**
```typescript
const [count, setCount] = useState(0);
// Always use functional updates when new state depends on old
setCount(prev => prev + 1); // Good
setCount(count + 1); // Avoid - can be stale in closures
```
**useReducer for complex state:**
When state has multiple related pieces that update together, or next state depends on previous state in complex ways.
**State management decision framework:**
1. **Local component state?** � useState
2. **Multiple related state updates?** � useReducer
3. **Shared across components?** � Context API or custom hook
4. **Need external library?** � Use codebase-investigator to find existing patterns, or internet-researcher to evaluate options (Zustand, Redux Toolkit, TanStack Query)
## Workflow: Handling Side Effects
**useEffect for external systems only** (API calls, subscriptions, browser APIs). NOT for derived state.
**Critical rules:**
- Always include all dependencies (ESLint: react-hooks/exhaustive-deps)
- Always return cleanup function (prevents memory leaks)
- Think "which state does this sync with?" not "when does this run?"
**Common pattern:**
```typescript
useEffect(() => {
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal })
.then(res => res.json())
.then(data => setData(data));
return () => controller.abort(); // Cleanup
}, []);
```
For comprehensive useEffect guidance (dependencies, cleanup, when NOT to use, debugging), see [useEffect-deep-dive.md](./useEffect-deep-dive.md).
## Workflow: Component Composition
**Children prop:** Use `children: React.ReactNode` for wrapping components.
**Custom hooks:** Extract reusable stateful logic (prefer over duplicating logic in components).
**Compound components:** For complex APIs like ``.
**Render props:** When component controls rendering but parent provides template.
## Workflow: Testing
**ALWAYS use codebase-investigator first** to find existing test patterns. Common approaches: React Testing Library, Playwright, Cypress.
See [react-testing.md](./react-testing.md) for comprehensive guidance.
## Performance
Profile before optimizing. Use `useMemo`, `useCallback`, `React.memo` only when measurements show need. React 19 compiler handles most memoization automatically.
## Common Rationalizations - STOP
| Excuse | Reality |
|--------|---------|
| "useEffect is fine for derived state" | Calculate derived values directly. useEffect for derived state causes extra renders and bugs. |
| "React.FC is the standard way" | Community moved away from React.FC. Use explicit function declarations with typed props. |
| "Cleanup doesn't matter for short operations" | Memory leaks are real. Always cleanup subscriptions, timers, and abort fetch requests. |
| "Missing dependencies is fine, I know what I'm doing" | Stale closures cause bugs. Always include all dependencies. Fix the root cause, don't lie to the linter. |
| "useCallback with all dependencies is correct" | Including state in deps creates new function every render AND stale closures. Use functional setState updates instead. |
| "This is Functional Core because it's pure logic" | Hooks with state are Imperative Shell or Mixed. Only pure functions without hooks are Functional Core. |
| "Array index as key is fine for static lists" | If list ever reorders, filters, or updates, you'll get bugs. Use stable unique IDs. |
| "Mutating state is faster" | React won't detect the change. Always create new objects/arrays. |
## Quick Reference
| Task | Pattern |
|------|---------|
| Props | `interface Props {...}; function Comp({ prop }: Props)` |
| State update | `setState(prev => newValue)` when depends on current |
| Fetch on mount | `useEffect(() => { fetch(...); return cleanup }, [])` |
| Derived value | Calculate directly, NOT useEffect |
| List render | `{items.map(item => )}` |
## Red Flags - STOP and Refactor
- `React.FC` in new code
- `useEffect` with state as only dependency
- Missing cleanup in useEffect
- Array index as key: `key={index}`
- Direct state mutation: `state.value = x`
- Missing dependencies in useEffect (suppressing ESLint warning)
- `any` type for props or event handlers
When you see these, refactor before proceeding.