Skill: ahooks

SkillFiles & storage

Utility hooks for React state management — grouped state and localStorage persistence. Use when managing grouped state that changes together, persisting state to localStorage, or coordinating state between URL and storage.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Skill: ahooks skill

What this skill tells your AI

The instructions your AI receives, as published by blockmatic/basilic in .agents/skills/ahooks-v3/SKILL.md and read by ahel’s review.

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 useSetState for grouped state that changes together (not URL-shareable)
  • Use useLocalStorageState for persistent state across browser sessions
  • Prefer nuqs for URL-shareable state over localStorage
  • Prefer TanStack Query for async operations and loading states
  • Use useState only for simple independent state (rare)

Constraints

MUST

  • Use useSetState for grouped state not in URL (form state, game engine state, ephemeral UI state)
  • Use useLocalStorageState for 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-v2 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

  1. URL-shareable state → Use nuqs (filters, search, tabs, pagination)
  2. Grouped state not in URL → Use useSetState (form state, game engine, ephemeral UI)
  3. Async operations → Use TanStack Query (data fetching, mutations, caching)
  4. localStorage persistence → Use useLocalStorageState (preferences, settings)
  5. 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

Signals

GitHub stars
89
Forks
11
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
ahooks-v3
Source
github.com/blockmatic/basilic