# State Mutation Hooks
This document describes the 5 new state mutation hooks added to `/hooks/`. These hooks provide reusable state management patterns for common React use cases.
## Overview
| Hook | Purpose | Return Type |
|------|---------|-------------|
| **useToggle** | Boolean state toggle | `{ value, toggle, setValue, setTrue, setFalse }` |
| **usePrevious** | Track previous value | `T \| undefined` |
| **useStateWithHistory** | State with undo/redo | `{ value, setValue, undo, redo, canUndo, canRedo, history }` |
| **useAsync** | Async function wrapper | `{ data, loading, error, execute, reset }` |
| **useUndo** | Simplified undo/redo | `{ value, setValue, undo, redo, reset, canUndo, canRedo }` |
## Detailed API Reference
### 1. useToggle
Boolean state management with multiple toggle options.
**Import:**
```typescript
import { useToggle } from '@/hooks/useToggle'
```
**Signature:**
```typescript
function useToggle(initialValue?: boolean): UseToggleReturn
interface UseToggleReturn {
value: boolean
toggle: () => void
setValue: (value: boolean | ((prev: boolean) => boolean)) => void
setTrue: () => void
setFalse: () => void
}
```
**Example:**
```typescript
const { value, toggle, setValue, setTrue, setFalse } = useToggle(false)
return (
Menu is {value ? 'open' : 'closed'}
)
```
**Use Cases:**
- Modal/dialog visibility
- Show/hide menu or panel
- Conditional rendering
- Toggle features on/off
---
### 2. usePrevious
Track the previous value of any state or prop across renders.
**Import:**
```typescript
import { usePrevious } from '@/hooks/usePrevious'
```
**Signature:**
```typescript
function usePrevious(value: T): T | undefined
```
**Example:**
```typescript
const [count, setCount] = useState(0)
const prevCount = usePrevious(count)
return (
Current: {count}
Previous: {prevCount ?? 'none'}
)
```
**Use Cases:**
- Detect value changes
- Compare current vs previous
- Form dirty state tracking
- Animation triggers based on value changes
- Conditional effects
**Important:** Returns `undefined` on first render.
---
### 3. useStateWithHistory
State management with full undo/redo history capability.
**Import:**
```typescript
import { useStateWithHistory } from '@/hooks/useStateWithHistory'
```
**Signature:**
```typescript
function useStateWithHistory(
initialValue: T,
options?: UseStateWithHistoryOptions
): UseStateWithHistoryReturn
interface UseStateWithHistoryOptions {
maxHistory?: number // default: 100
}
interface UseStateWithHistoryReturn {
value: T
setValue: (value: T | ((prev: T) => T)) => void
undo: () => void
redo: () => void
canUndo: boolean
canRedo: boolean
history: T[]
}
```
**Example:**
```typescript
const { value, setValue, undo, redo, canUndo, canRedo, history } = useStateWithHistory('initial')
return (
Current: {value}
History size: {history.length}
setValue(e.target.value)} />
)
```
**Use Cases:**
- Text editor undo/redo
- Form draft history
- Canvas drawing operations
- Configuration changes tracking
- Multi-step workflows
**Features:**
- Limits history size (configurable)
- Removes "future" history when new value set after undo
- Full history array accessible
- Type-safe for any value type
---
### 4. useAsync
Async function wrapper with automatic loading, error, and data state management.
**Import:**
```typescript
import { useAsync } from '@/hooks/useAsync'
```
**Signature:**
```typescript
function useAsync(
asyncFunction: (...args: any[]) => Promise,
deps?: any[],
options?: UseAsyncOptions
): UseAsyncReturn
interface UseAsyncOptions {
immediate?: boolean // default: false - execute on mount
resetErrorOnRetry?: boolean // default: true
resetDataOnRetry?: boolean // default: false
}
interface UseAsyncReturn {
data: T | undefined
loading: boolean
error: Error | undefined
execute: (...args: any[]) => Promise
reset: () => void
}
```
**Example - Manual Execution:**
```typescript
const fetchUser = async (userId: string) => {
const res = await fetch(`/api/users/${userId}`)
return res.json()
}
const { data, loading, error, execute } = useAsync(fetchUser)
return (
)
```
**Use Cases:**
- API data fetching
- Async operations with loading states
- Error handling and user feedback
- Retry mechanisms
- Form submissions
**Features:**
- Prevents state updates after unmount
- Configurable error/data reset on retry
- Pass arguments to async function
- Reset all states
---
### 5. useUndo
Simplified undo/redo wrapper for any value, lighter than `useStateWithHistory`.
**Import:**
```typescript
import { useUndo } from '@/hooks/useUndo'
```
**Signature:**
```typescript
function useUndo(initialValue: T): UseUndoReturn
interface UseUndoReturn {
value: T
setValue: (value: T | ((prev: T) => T)) => void
undo: () => void
redo: () => void
reset: (value?: T) => void
canUndo: boolean
canRedo: boolean
}
```
**Example:**
```typescript
const { value, setValue, undo, redo, reset, canUndo, canRedo } = useUndo({ x: 0, y: 0 })
return (
)
```
**Use Cases:**
- Simple undo/redo without full history
- Lightweight state tracking
- Form value changes
- Canvas position/zoom
- Configuration adjustments
**Differences from `useStateWithHistory`:**
- No maxHistory limit (stores only past, present, future)
- Simpler implementation, smaller bundle
- Good for finite undo/redo scenarios
- No history array access
---
## Comparison Table
| Feature | useToggle | usePrevious | useStateWithHistory | useAsync | useUndo |
|---------|-----------|-------------|--------------------|---------|----|
| Tracks state | ✓ | ✗ (read-only) | ✓ | ✓ (data) | ✓ |
| Undo capability | ✗ | ✗ | ✓ | ✗ | ✓ |
| History array | ✗ | ✗ | ✓ | ✗ | ✗ |
| Async support | ✗ | ✗ | ✗ | ✓ | ✗ |
| Bundle size | Small | Tiny | Medium | Medium | Small |
| Generic typing | ✗ (boolean) | ✓ | ✓ | ✓ | ✓ |
---
## Installation & Usage
All hooks are located in `/hooks/` and can be imported directly:
```typescript
import { useToggle } from '@/hooks/useToggle'
import { usePrevious } from '@/hooks/usePrevious'
import { useStateWithHistory } from '@/hooks/useStateWithHistory'
import { useAsync } from '@/hooks/useAsync'
import { useUndo } from '@/hooks/useUndo'
```
Or using absolute imports:
```typescript
import { useToggle } from '/path/to/hooks/useToggle'
```
---
## Best Practices
1. **useToggle** - Use for simple boolean states. Don't overcomplicate with extra logic.
2. **usePrevious** - Always check for `undefined` on first render.
3. **useStateWithHistory** - Set reasonable `maxHistory` limits to prevent memory issues.
4. **useAsync** - Always handle the `error` state for better UX.
5. **useUndo** - Use for lightweight undo/redo, not complex workflows.
---
## Performance Considerations
- All hooks use `useCallback` to memoize functions where appropriate
- `useAsync` prevents state updates after unmount
- `useStateWithHistory` includes configurable history size limits
- `usePrevious` uses `useRef` (no re-renders)
- `useToggle` and `useUndo` are optimized for minimal re-renders