ahooks
Skill: ahooks
Scope
- Applies to: ahooks v3+ utility hooks for React state management, grouped state updates, localStorage persistence
- Does NOT cover: Data fetching (use TanStack Query), URL state management (use nuqs), complex state machines, async operations
Assumptions
- ahooks v3+
- React 18+ with hooks support
- TypeScript v5+ (for type inference)
- Client-side only (hooks require browser APIs for localStorage)
Principles
- Use
useSetStatefor grouped state that changes together (not URL-shareable) - Use
useLocalStorageStatefor persistent state across browser sessions - Prefer nuqs for URL-shareable state over localStorage
- Prefer TanStack Query for async operations and loading states
- Use
useStateonly for simple independent state (rare)
Constraints
MUST
- Use
useSetStatefor grouped state not in URL (form state, game engine state, ephemeral UI state) - Use
useLocalStorageStatefor localStorage persistence
SHOULD
- Prefer nuqs for URL-shareable state over localStorage
- Prefer TanStack Query for async operations and loading states
- Use TypeScript generics for type-safe state:
useLocalStorageState<boolean>('key', { defaultValue: false })
AVOID
- Using for URL state (use nuqs instead)
- Using for loading/error states (use TanStack Query instead)
- Using for complex async operations (use TanStack Query instead)
- Mixing URL state with localStorage without explicit sync logic
Interactions
- Complements nuqs for URL state management (can sync bidirectionally)
- Complements TanStack Query for async operations (use TanStack Query for data fetching)
- Part of state management decision tree (see React rules)
- Works with React 18+ hooks architecture
Patterns
useSetState Pattern
Use for grouped state that updates together:
import { useSetState } from 'ahooks'
const [state, setState] = useSetState({
name: '',
email: '',
age: 0,
})
// Partial updates (shallow merge)
setState({ name: 'John' })
setState(prev => ({ ...prev, email: 'john@example.com' }))
When to use: Form state, game engine state, UI state that changes together (if not URL-shareable)
When NOT to use: URL-shareable state (use nuqs), loading states (use TanStack Query)
useLocalStorageState Pattern
Use for state that persists across browser sessions:
import { useLocalStorageState } from 'ahooks'
const [value, setValue] = useLocalStorageState<boolean>('key', {
defaultValue: false,
})
// Type-safe with generics
const [settings, setSettings] = useLocalStorageState<Settings>('settings', {
defaultValue: { theme: 'light', fontSize: 14 },
})
When to use: User preferences, debug flags, settings that should persist across sessions
When NOT to use: URL-shareable state (use nuqs), sensitive data (use secure storage)
Integration with nuqs
Bidirectional sync between URL and localStorage:
import { useLocalStorageState } from 'ahooks'
import { useQueryState } from 'nuqs'
import { useEffect, useRef } from 'react'
const [queryState, setQueryState] = useQueryState('debug')
const [storageState, setStorageState] = useLocalStorageState<boolean>('debug', {
defaultValue: false,
})
const isFirstMount = useRef(true)
// Sync on mount: localStorage → URL
useEffect(() => {
if (isFirstMount.current) {
isFirstMount.current = false
if (storageState && queryState !== 'true') {
setQueryState('true')
return
}
}
// Sync changes: URL → localStorage
if (queryState === 'true' && !storageState) {
setStorageState(true)
} else if (queryState === 'false' && storageState) {
setStorageState(false)
}
}, [queryState, storageState, setQueryState, setStorageState])
Use case: Debug flags, feature toggles that should be both URL-shareable and persistent
State Management Decision Tree
- URL-shareable state → Use
nuqs(filters, search, tabs, pagination) - Grouped state not in URL → Use
useSetState(form state, game engine, ephemeral UI) - Async operations → Use TanStack Query (data fetching, mutations, caching)
- localStorage persistence → Use
useLocalStorageState(preferences, settings) - Simple independent state → Use
useState(rare, prefer other options)
References
- ahooks documentation - Official documentation
- React rules - State management decision tree and patterns
- TanStack Query - Async operations and data fetching patterns
More from blockmatic/basilic
hey api codegen
|
36typescript-advanced-patterns
Advanced TypeScript patterns for type-safe, maintainable code using sophisticated type system features. Use when building type-safe APIs, implementing complex domain models, or leveraging TypeScript's advanced type capabilities.
28drizzle orm
|
27emilkowal-animations
Emil Kowalski's animation best practices for web interfaces. Use when writing, reviewing, or implementing animations in React, CSS, or Framer Motion. Triggers on tasks involving transitions, easing, gestures, toasts, drawers, or motion.
27vercel-react-best-practices
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
26tailwind-design-system
Build scalable design systems with Tailwind CSS v4, design tokens, component libraries, and responsive patterns. Use when creating component libraries, implementing design systems, or standardizing UI patterns.
19