8.4 KiB
Complete Hook Library Reference
Overview
The CodeForge hook library provides comprehensive, reusable React hooks organized by domain. All hooks are under 150 LOC, fully typed, and designed for composition.
Organization
src/hooks/
├── data/ # Data management hooks
├── ui/ # UI state management hooks
├── forms/ # Form and validation hooks
├── feature-ideas/ # Feature-specific hooks
├── core/ # Core utility hooks
├── ai/ # AI integration hooks
└── orchestration/ # JSON orchestration hooks
Data Management Hooks
useArray<T>(key, defaultValue)
Enhanced array management with persistence.
Features:
- Add/remove items
- Update items with predicates
- Find and filter operations
- Auto-persists to KV store
Example:
import { useArray } from '@/hooks/data'
const { items, add, remove, update, find, count } = useArray<Todo>('todos', [])
add({ id: '1', text: 'Learn hooks', done: false })
update(
(todo) => todo.id === '1',
(todo) => ({ ...todo, done: true })
)
remove((todo) => todo.done)
useCRUD<T>(items, setItems)
Complete CRUD operations for entity management.
Features:
- Create, read, update, delete operations
- Selection management
- Duplicate functionality
- Type-safe operations
Example:
import { useCRUD } from '@/hooks/data'
import { useKV } from '@github/spark/hooks'
const [tasks, setTasks] = useKV('tasks', [])
const {
create,
update,
remove,
selected,
setSelectedId
} = useCRUD(tasks, setTasks)
create({ id: '1', name: 'New Task', status: 'pending' })
update('1', { status: 'completed' })
setSelectedId('1')
useSearch<T>(items, searchKeys, debounceMs)
Debounced search across multiple fields.
Features:
- Multi-field search
- Debounced input
- Type-safe key selection
- Performance optimized
Example:
import { useSearch } from '@/hooks/data'
const { query, setQuery, results, isSearching } = useSearch(
users,
['name', 'email', 'role'],
300
)
// In your component
<Input value={query} onChange={(e) => setQuery(e.target.value)} />
{results.map(user => <UserCard key={user.id} user={user} />)}
useDebounce<T>(value, delay)
Debounce any value changes.
Example:
import { useDebounce } from '@/hooks/data'
const [input, setInput] = useState('')
const debouncedInput = useDebounce(input, 500)
useEffect(() => {
// API call with debounced value
fetchResults(debouncedInput)
}, [debouncedInput])
useSort<T>(items, defaultKey)
Sort items by any key with direction toggle.
Features:
- String, number, and generic comparison
- Toggle ascending/descending
- Type-safe sort keys
Example:
import { useSort } from '@/hooks/data'
const { sortedItems, sortKey, sortDirection, toggleSort } = useSort(
products,
'name'
)
<Button onClick={() => toggleSort('price')}>
Sort by Price {sortKey === 'price' && (sortDirection === 'asc' ? '↑' : '↓')}
</Button>
usePagination<T>(items, initialPageSize)
Client-side pagination with full controls.
Features:
- Page navigation
- Dynamic page size
- Has next/prev indicators
- Total page calculation
Example:
import { usePagination } from '@/hooks/data'
const {
items,
page,
totalPages,
nextPage,
prevPage,
goToPage,
hasNext,
hasPrev
} = usePagination(allItems, 20)
<Button onClick={prevPage} disabled={!hasPrev}>Previous</Button>
<span>Page {page} of {totalPages}</span>
<Button onClick={nextPage} disabled={!hasNext}>Next</Button>
UI State Hooks
useDialog(initialOpen)
Simple dialog/modal state management.
Example:
import { useDialog } from '@/hooks/ui'
const { isOpen, open, close, toggle } = useDialog()
<Button onClick={open}>Open Dialog</Button>
<Dialog open={isOpen} onOpenChange={(open) => open ? open() : close()}>
...
</Dialog>
useTabs<T>(defaultTab)
Type-safe tab navigation.
Example:
import { useTabs } from '@/hooks/ui'
const { activeTab, switchTab, isActive } = useTabs<'overview' | 'details' | 'settings'>('overview')
<Tabs value={activeTab} onValueChange={switchTab}>
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="details">Details</TabsTrigger>
</TabsList>
</Tabs>
useSelection<T>()
Multi-select state management.
Features:
- Select/deselect individual items
- Select all/deselect all
- Toggle selection
- Selection count
Example:
import { useSelection } from '@/hooks/ui'
const {
selectedIds,
toggle,
selectAll,
deselectAll,
isSelected,
count
} = useSelection()
<Checkbox
checked={isSelected(item.id)}
onCheckedChange={() => toggle(item.id)}
/>
{count > 0 && <Badge>{count} selected</Badge>}
useClipboard(successMessage)
Copy to clipboard with feedback.
Example:
import { useClipboard } from '@/hooks/ui'
const { copied, copy } = useClipboard('Copied to clipboard!')
<Button onClick={() => copy(codeSnippet)}>
{copied ? 'Copied!' : 'Copy'}
</Button>
Form Hooks
useFormField<T>(initialValue, rules)
Single form field with validation.
Features:
- Validation rules
- Touch state
- Error messages
- Reset functionality
Example:
import { useFormField } from '@/hooks/forms'
const email = useFormField('', [
{
validate: (v) => v.includes('@'),
message: 'Invalid email'
},
{
validate: (v) => v.length > 0,
message: 'Email required'
}
])
<Input
value={email.value}
onChange={(e) => email.onChange(e.target.value)}
onBlur={email.onBlur}
/>
{email.touched && email.error && <span>{email.error}</span>}
useForm<T>(config)
Complete form management with validation.
Features:
- Multi-field state
- Validation schema
- Async submit handling
- Touch tracking per field
Example:
import { useForm } from '@/hooks/forms'
const form = useForm({
initialValues: {
name: '',
email: '',
message: ''
},
validate: (values) => {
const errors: Record<string, string> = {}
if (!values.email.includes('@')) {
errors.email = 'Invalid email'
}
return errors
},
onSubmit: async (values) => {
await api.submitForm(values)
toast.success('Form submitted!')
}
})
<form onSubmit={form.handleSubmit}>
<Input
value={form.values.email}
onChange={(e) => form.setValue('email', e.target.value)}
/>
{form.errors.email && <span>{form.errors.email}</span>}
<Button type="submit" disabled={form.isSubmitting}>
{form.isSubmitting ? 'Submitting...' : 'Submit'}
</Button>
</form>
Hook Composition
Hooks are designed to be composed together:
import { useArray, useSearch, useSort, usePagination } from '@/hooks/data'
import { useSelection } from '@/hooks/ui'
function useProductList() {
const { items, add, remove, update } = useArray<Product>('products', [])
const { results, query, setQuery } = useSearch(items, ['name', 'category'])
const { sortedItems, toggleSort } = useSort(results, 'name')
const { items: pagedItems, ...pagination } = usePagination(sortedItems, 10)
const selection = useSelection<Product>()
return {
products: pagedItems,
add,
remove,
update,
search: { query, setQuery },
sort: { toggleSort },
pagination,
selection,
}
}
Best Practices
- Keep hooks focused: One responsibility per hook
- Use composition: Combine simple hooks for complex behavior
- Type everything: Leverage TypeScript for safety
- Handle loading/error: Always consider async states
- Memoize callbacks: Use
useCallbackfor stable references - Document dependencies: Clear about what causes re-renders
Performance Tips
- Use
useCallbackanduseMemowhere appropriate - Avoid creating new objects/arrays in render
- Leverage the functional update pattern for
setState - Consider
useTransitionfor non-urgent updates - Profile with React DevTools
Testing Hooks
import { renderHook, act } from '@testing-library/react'
import { useArray } from '@/hooks/data'
test('useArray adds items correctly', () => {
const { result } = renderHook(() => useArray('test-key', []))
act(() => {
result.current.add({ id: '1', name: 'Test' })
})
expect(result.current.items).toHaveLength(1)
expect(result.current.items[0].name).toBe('Test')
})