---
name: react-component-split
category: software-development
description: Split large React client components (>300 lines) into multi-file architecture with hooks, helpers, types, and sub-components. Preserves behavior while improving maintainability.
---

# React Component Split

## When to use
- Single file > 300-400 lines of JSX + logic
- Multiple distinct UI sections (tabs, cards, tables, forms) in one file
- Helper functions, state, and mutations all mixed together
- User explicitly requests or the pattern is identified during review

## Target structure
```
src/path/ComponentsName.tsx          # Orchestrator (~100-200 lines)
src/path/types.ts                    # All interfaces, types, constants
src/path/helpers.ts                  # Pure utility/formatting functions
src/path/hooks/useComponentData.ts   # State + data fetching + mutations
src/path/components/
├── FormComponent.tsx                # Add/edit forms
├── DetailTable.tsx                  # Data tables with sorting/filtering
├── SummaryCards.tsx                 # Statistics/summary cards
└── AnotherSection.tsx               # Any other logical UI section
```

## Step-by-step process

1. **Audit the monolith**
   ```bash
   wc -l path/to/MonolithComponent.tsx
   ```
   Read the entire file to identify sections:
   - Types/interfaces (interfaces, type aliases, const records)
   - Pure helpers (formatting, calculations, transformations)
   - State setup (`useState` for each concern)
   - Data loading (`useEffect` + `fetch`/`useCallback`)
   - UI sections (tabs, cards, tables, forms)

2. **Create types.ts**
   - Extract all `interface` and `type` declarations
   - Move const records used across files
   - Export everything explicitly

3. **Create helpers.ts**
   - Move pure functions that don't depend on component state
   - Functions that take inputs and return outputs with no side effects
   - Formatting, date math, calculation helpers
   - Include type imports from types.ts if needed
   - **Import path: use `./types` not `../types` (same directory)**

4. **Create hooks/useComponentData.ts**
   - Group related `useState` into logical chunks
   - Move `useCallback` for data loading
   - Move `useEffect` for initial loads
   - Move mutation functions (add, delete, save, update)
   - Sort toggle functions belong here too
   - Return everything the orchestrator needs via a single object

5. **Create UI sub-components** (one file per section)
   - Each component receives only what it needs via props
   - Use TypeScript interfaces for prop types
   - Keep forms, tables, cards each in their own file
   - Re-use SortButton helpers where needed
   - **Watch out**: If a component needs dirty state keys, ensure consistency with the hook

6. **Rewrite orchestrator**
   - Import the hook and all UI components
   - Wire up props and callbacks
   - Keep only state that spans multiple UI sections
   - Keep only calculations needed for multiple child components
   - Should be 100-200 lines max

7. **Verify**
   ```bash
   cd /path/to/project && npx tsc --noEmit --pretty 2>&1 | head -80
   ```
   Fix any type errors before committing.

## Execution notes

- **Do NOT delegate to subagents** for files > 800 lines — the context volume (100K+ tokens to read + reason about the full file) causes timeouts. Do it directly in your session with sequential write_file/patch calls.
- Write files in this order: types.ts → helpers.ts → hook → UI components → orchestrator. Each step validates imports from previous files.
- After writing all files, run `tsc --noEmit` before committing. Fix errors iteratively.

## Common pitfalls

- **Dirty state key mismatch**: If the hook uses `${activeTab}-${entry.id}` as a key for dirty entries, ensure sub-components use the exact same formula.
- **Helpers import path**: When creating helpers.ts in the same directory as types.ts, import as `./types` not `../types`.
- **Hardcoded values in helpers**: Extract values like `penalDiario` and `diaVencimiento` to be passed as props rather than hardcoding in extracted components.
- **Sort button onClick**: When recreating SortButton patterns, ensure the onClick handler is properly wired through (use the pattern from original code or re-export from table controls).
- **Filtered totals**: Ensure computed filtered totals (e.g., filteredPagosServicios) are calculated from the already-filtered array, not from the original data.
- **Closure dependencies**: Functions that depend on state (like `getPorcentaje`) may need to be recalculated in the orchestrator where the latest state is available, not in sub-components with stale props.

## Commit message pattern
```
refactor: split MonolithComponent.tsx (1141 -> 8 files, max 379 lines)

- types.ts (...)
- helpers.ts (...)  
- hooks/useData.ts (...)
- components: SummaryCards.tsx, Form.tsx, Table1.tsx, Table2.tsx
- MonolithClient.tsx (orchestrator)
- 0 tsc errors, behavior unchanged
```