# Custom Hooks

## Filosofía

En el nuevo stack, los hooks tienen propósitos específicos:

| Tipo de Hook | Librería | Propósito |
|--------------|----------|-----------|
| Data fetching | TanStack Query | `useQuery`, `useMutation` |
| UI state | Zustand | `useUIStore` |
| Custom logic | React | Lógica de negocio, cálculos |

---

## Hooks de Data (TanStack Query)

Ver `patterns/tanstack-query.md` para documentación completa.

**Ubicación:** `src/hooks/use[Entity].ts`

```typescript
// hooks/useAccounts.ts
import { useQuery } from '@tanstack/react-query';
import { getAccounts } from '../services/repositories/accountsRepository';

export function useAccounts() {
  return useQuery({
    queryKey: ['accounts'],
    queryFn: ({ signal }) => getAccounts(signal),
  });
}
```

---

## Hooks de UI State (Zustand)

Ver `patterns/zustand.md` para documentación completa.

**Ubicación:** `src/store/use[Domain]Store.ts`

```typescript
// Uso directo del store
const { selectedId, setSelectedId } = useUIStore();

// Con selector (mejor performance)
const selectedId = useUIStore(state => state.selectedId);
```

---

## Hooks de Lógica Custom

Para lógica que no es data ni UI state:

**Ubicación:** `src/hooks/use[Functionality].ts`

### Ejemplo: Hook de Formateo

```typescript
// hooks/useCurrency.ts
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';

export function useCurrency() {
  const { i18n } = useTranslation();

  const format = useCallback((amount: number) => {
    return new Intl.NumberFormat(i18n.language, {
      style: 'currency',
      currency: 'USD',
    }).format(amount);
  }, [i18n.language]);

  return { format };
}
```

### Ejemplo: Hook de Debounce

```typescript
// hooks/useDebounce.ts
import { useState, useEffect } from 'react';

export function useDebounce<T>(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedValue(value), delay);
    return () => clearTimeout(timer);
  }, [value, delay]);

  return debouncedValue;
}
```

### Ejemplo: Hook de Media Query

```typescript
// hooks/useMediaQuery.ts
import { useState, useEffect } from 'react';

export function useMediaQuery(query: string): boolean {
  const [matches, setMatches] = useState(
    () => window.matchMedia(query).matches
  );

  useEffect(() => {
    const mediaQuery = window.matchMedia(query);
    const handler = (e: MediaQueryListEvent) => setMatches(e.matches);

    mediaQuery.addEventListener('change', handler);
    return () => mediaQuery.removeEventListener('change', handler);
  }, [query]);

  return matches;
}
```

---

## Naming Conventions

| Patrón | Ejemplo | Uso |
|--------|---------|-----|
| `use[Entity]` | `useAccounts` | Query para lista |
| `use[Entity]` | `useAccount(id)` | Query para detalle |
| `useCreate[Entity]` | `useCreateAccount` | Mutation crear |
| `useUpdate[Entity]` | `useUpdateAccount` | Mutation actualizar |
| `useDelete[Entity]` | `useDeleteAccount` | Mutation eliminar |
| `use[Domain]Store` | `useUIStore` | Zustand store |
| `use[Functionality]` | `useDebounce` | Lógica custom |

---

## Anti-Patrones

### ❌ NO: useEffect para fetch

```typescript
// MAL - Patrón obsoleto
function useAccounts() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    getAccounts().then(setData).finally(() => setLoading(false));
  }, []);

  return { data, loading };
}
```

### ❌ NO: Estado local para server data

```typescript
// MAL - Duplica estado
function Component() {
  const { data } = useAccounts();
  const [accounts, setAccounts] = useState(data); // ❌ Innecesario
}
```

### ❌ NO: Lógica de fetch en componentes

```typescript
// MAL - Fetch directo en componente
function Component() {
  useEffect(() => {
    fetch('/api/accounts').then(/*...*/); // ❌ Usar useQuery
  }, []);
}
```

---

## Estructura de Carpetas

```
src/
├── hooks/
│   ├── useAccounts.ts        # Query hooks
│   ├── useMovements.ts
│   ├── useCreateAccount.ts   # Mutation hooks
│   ├── useDebounce.ts        # Utility hooks
│   └── index.ts              # Re-exports
├── store/
│   ├── useUIStore.ts         # UI state
│   └── useWizardStore.ts     # (si aplica)
```

---

## Checklist

- [ ] ¿Es data fetching? → useQuery/useMutation
- [ ] ¿Es UI state? → Zustand store
- [ ] ¿Es lógica pura? → Custom hook con React
- [ ] ¿Nombre sigue convención? → use[Descriptor]
