React Hooks - Patterns & ahooks Library
When working with React/Preact components:
- Identify opportunities for custom hook extraction
- Always check if ahooks has a hook before writing custom implementations
ahooks - Prefer Over Custom Implementations
ahooks is a high-quality React hooks library. Before
writing custom hooks, check if ahooks already provides what you need.
Exclude: useRequest - use TanStack Query instead for data fetching.
Quick Reference by Use Case
| Need |
ahooks Hook |
Instead of |
| Boolean state |
useBoolean |
useState(false) + toggle fn |
| Toggle between values |
useToggle |
useState + manual toggle |
| Counter |
useCounter |
useState(0) + inc/dec fns |
| Object state |
useSetState |
useState({}) + spread merging |
| Map data |
useMap |
useState(new Map()) |
| Set data |
useSet |
useState(new Set()) |
| localStorage |
useLocalStorageState |
useState + useEffect sync |
| sessionStorage |
useSessionStorageState |
useState + useEffect sync |
| Cookies |
useCookieState |
manual cookie handling |
| Debounce value |
useDebounce |
custom debounce logic |
| Debounce function |
useDebounceFn |
lodash.debounce wrapper |
| Throttle value |
useThrottle |
custom throttle logic |
| Throttle function |
useThrottleFn |
lodash.throttle wrapper |
| Interval |
useInterval |
setInterval + cleanup |
| Timeout |
useTimeout |
setTimeout + cleanup |
| Previous value |
usePrevious |
useRef pattern |
| Mount callback |
useMount |
useEffect(() => {}, []) |
| Unmount callback |
useUnmount |
useEffect(() => cleanup, []) |
| Click outside |
useClickAway |
manual event listener |
| Hover state |
useHover |
onMouseEnter/Leave handlers |
| Key press |
useKeyPress |
keyboard event listener |
| Mouse position |
useMouse |
mousemove listener |
| Scroll position |
useScroll |
scroll listener |
| Element size |
useSize |
ResizeObserver |
| In viewport |
useInViewport |
IntersectionObserver |
| Network status |
useNetwork |
navigator.onLine + events |
| Document visibility |
useDocumentVisibility |
visibilitychange event |
| Fullscreen |
useFullscreen |
Fullscreen API |
| Page title |
useTitle |
document.title = x |
| Favicon |
useFavicon |
manual link manipulation |
| Lock async fn |
useLockFn |
manual loading state |
| Virtual list |
useVirtualList |
custom virtualization |
| Drag/Drop |
useDrag / useDrop |
HTML5 drag events |
| Selections |
useSelections |
manual selection state |
| History travel |
useHistoryTravel |
undo/redo state |
| Mutation observer |
useMutationObserver |
MutationObserver API |
| Text selection |
useTextSelection |
Selection API |
| Responsive |
useResponsive |
media query listeners |
| Deep compare effect |
useDeepCompareEffect |
custom deep comparison |
| RAF timing |
useRafInterval / useRafTimeout |
requestAnimationFrame |
Detailed hook documentation: $file: ./ahooks/index.md
When to Apply
- Reviewing React/Preact component code
- Creating new components with stateful logic
- Editing existing components
- Code review discussions about React patterns
Hook Extraction Signals
Strong Candidates for Custom Hooks
Repeated useState + useEffect pairs
- Same state + side effect pattern in multiple components
- Example: loading state + fetch logic
Complex useEffect with cleanup
- Event listeners, subscriptions, timers
- Example: window resize listener, intersection observer
State machines / multi-step state
- Related state variables that change together
- Example: form state (values, errors, touched, submitting)
Browser API interactions
- localStorage, sessionStorage, navigator APIs
- Example:
useLocalStorage, useGeolocation
Debounced/throttled values
- Any value that needs timing control
- Example: search input, scroll position
Media queries / responsive logic
- Breakpoint detection, orientation changes
- Example:
useMediaQuery, useBreakpoint
Weak Candidates (Usually Keep Inline)
- Single useState with simple updates
- useEffect that only runs once on mount with no cleanup
- Component-specific logic unlikely to be reused
Extraction Pattern
// Before: Logic scattered in component
function Component() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetchData().then(setData).catch(setError).finally(() => setLoading(false));
}, []);
// ... render
}
// After: Extracted to custom hook
function useAsyncData(fetchFn) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetchFn().then(setData).catch(setError).finally(() => setLoading(false));
}, [fetchFn]);
return { data, loading, error };
}
function Component() {
const { data, loading, error } = useAsyncData(fetchData);
// ... render
}
Naming Conventions
- Prefix with
use
- Describe what it manages, not how:
useAuth not useAuthStateAndEffects
- Be specific:
useLocalStorage not useStorage
When Suggesting Hooks
Provide:
- The pattern you spotted
- Suggested hook name
- Brief extraction sketch
- Reuse potential (how many places could use this?)
Don't:
- Suggest hooks for trivial single-use logic
- Over-abstract stable, simple code
- Force extraction when inline is clearer
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: react-hooks-33description: React hook patterns and ahooks library usage. Apply when working with React/Preact components to identify hook extraction opportunities and recommend ahooks alternatives to manual implementations. Use when this capability is needed.4---56# React Hooks - Patterns & ahooks Library78When working with React/Preact components:91. Identify opportunities for custom hook extraction102. **Always check if ahooks has a hook** before writing custom implementations1112## ahooks - Prefer Over Custom Implementations1314[ahooks](https://ahooks.js.org/) is a high-quality React hooks library. Before15writing custom hooks, check if ahooks already provides what you need.1617**Exclude**: `useRequest` - use TanStack Query instead for data fetching.1819### Quick Reference by Use Case2021| Need | ahooks Hook | Instead of |22|------|-------------|------------|23| Boolean state | `useBoolean` | `useState(false)` + toggle fn |24| Toggle between values | `useToggle` | `useState` + manual toggle |25| Counter | `useCounter` | `useState(0)` + inc/dec fns |26| Object state | `useSetState` | `useState({})` + spread merging |27| Map data | `useMap` | `useState(new Map())` |28| Set data | `useSet` | `useState(new Set())` |29| localStorage | `useLocalStorageState` | `useState` + `useEffect` sync |30| sessionStorage | `useSessionStorageState` | `useState` + `useEffect` sync |31| Cookies | `useCookieState` | manual cookie handling |32| Debounce value | `useDebounce` | custom debounce logic |33| Debounce function | `useDebounceFn` | lodash.debounce wrapper |34| Throttle value | `useThrottle` | custom throttle logic |35| Throttle function | `useThrottleFn` | lodash.throttle wrapper |36| Interval | `useInterval` | `setInterval` + cleanup |37| Timeout | `useTimeout` | `setTimeout` + cleanup |38| Previous value | `usePrevious` | useRef pattern |39| Mount callback | `useMount` | `useEffect(() => {}, [])` |40| Unmount callback | `useUnmount` | `useEffect(() => cleanup, [])` |41| Click outside | `useClickAway` | manual event listener |42| Hover state | `useHover` | onMouseEnter/Leave handlers |43| Key press | `useKeyPress` | keyboard event listener |44| Mouse position | `useMouse` | mousemove listener |45| Scroll position | `useScroll` | scroll listener |46| Element size | `useSize` | ResizeObserver |47| In viewport | `useInViewport` | IntersectionObserver |48| Network status | `useNetwork` | navigator.onLine + events |49| Document visibility | `useDocumentVisibility` | visibilitychange event |50| Fullscreen | `useFullscreen` | Fullscreen API |51| Page title | `useTitle` | `document.title = x` |52| Favicon | `useFavicon` | manual link manipulation |53| Lock async fn | `useLockFn` | manual loading state |54| Virtual list | `useVirtualList` | custom virtualization |55| Drag/Drop | `useDrag` / `useDrop` | HTML5 drag events |56| Selections | `useSelections` | manual selection state |57| History travel | `useHistoryTravel` | undo/redo state |58| Mutation observer | `useMutationObserver` | MutationObserver API |59| Text selection | `useTextSelection` | Selection API |60| Responsive | `useResponsive` | media query listeners |61| Deep compare effect | `useDeepCompareEffect` | custom deep comparison |62| RAF timing | `useRafInterval` / `useRafTimeout` | requestAnimationFrame |6364**Detailed hook documentation**: `$file: ./ahooks/index.md`6566## When to Apply6768- Reviewing React/Preact component code69- Creating new components with stateful logic70- Editing existing components71- Code review discussions about React patterns7273## Hook Extraction Signals7475### Strong Candidates for Custom Hooks76771. **Repeated useState + useEffect pairs**78 - Same state + side effect pattern in multiple components79 - Example: loading state + fetch logic80812. **Complex useEffect with cleanup**82 - Event listeners, subscriptions, timers83 - Example: window resize listener, intersection observer84853. **State machines / multi-step state**86 - Related state variables that change together87 - Example: form state (values, errors, touched, submitting)88894. **Browser API interactions**90 - localStorage, sessionStorage, navigator APIs91 - Example: `useLocalStorage`, `useGeolocation`92935. **Debounced/throttled values**94 - Any value that needs timing control95 - Example: search input, scroll position96976. **Media queries / responsive logic**98 - Breakpoint detection, orientation changes99 - Example: `useMediaQuery`, `useBreakpoint`100101### Weak Candidates (Usually Keep Inline)102103- Single useState with simple updates104- useEffect that only runs once on mount with no cleanup105- Component-specific logic unlikely to be reused106107## Extraction Pattern108109```tsx110// Before: Logic scattered in component111function Component() {112 const [data, setData] = useState(null);113 const [loading, setLoading] = useState(true);114 const [error, setError] = useState(null);115116 useEffect(() => {117 fetchData().then(setData).catch(setError).finally(() => setLoading(false));118 }, []);119120 // ... render121}122123// After: Extracted to custom hook124function useAsyncData(fetchFn) {125 const [data, setData] = useState(null);126 const [loading, setLoading] = useState(true);127 const [error, setError] = useState(null);128129 useEffect(() => {130 fetchFn().then(setData).catch(setError).finally(() => setLoading(false));131 }, [fetchFn]);132133 return { data, loading, error };134}135136function Component() {137 const { data, loading, error } = useAsyncData(fetchData);138 // ... render139}140```141142## Naming Conventions143144- Prefix with `use`145- Describe what it manages, not how: `useAuth` not `useAuthStateAndEffects`146- Be specific: `useLocalStorage` not `useStorage`147148## When Suggesting Hooks149150Provide:1511. The pattern you spotted1522. Suggested hook name1533. Brief extraction sketch1544. Reuse potential (how many places could use this?)155156Don't:157- Suggest hooks for trivial single-use logic158- Over-abstract stable, simple code159- Force extraction when inline is clearer160161---162> Converted and distributed by [TomeVault](https://tomevault.io/claim/dungle-scrubs) — claim your Tome and manage your conversions.163<!-- tomevault:4.0:skill_md:2026-04-15 -->