# createDeepCompareEffect (/docs/createDeepCompareEffect) ## Overview * createDeepCompareEffect is a React hook that works similarly to useEffect but performs a deep comparison of its dependencies. This means that the effect will only re-run if the actual content of the dependencies changes, rather than just their references. \## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/createDeepCompareEffect.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/createDeepCompareEffect.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/createDeepCompareEffect.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/createDeepCompareEffect.json ``` ## Usage ```ts ``` ## API # createUpdateEffect (/docs/createUpdateEffect) ## Overview * createUpdateEffect is a React hook that works similarly to useEffect but performs a deep comparison of its dependencies. This means that the effect will only re-run if the actual content of the dependencies changes, rather than just their references. \## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/createUpdateEffect.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/createUpdateEffect.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/createUpdateEffect.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/createUpdateEffect.json ``` ## Usage ```ts ``` ## API # Get Started (/docs) ## Getting Started Welcome to **shadcn-ahooks**! This documentation will help you get started with using the library effectively. This Registry provides a collection of React hooks from the popular [ahooks](https://ahooks.js.org/) library, packaged for easy integration with shadcn UI projects. ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/shadcn-ahooks.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/shadcn-ahooks.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/shadcn-ahooks.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/shadcn-ahooks.json ``` ## Overview The `src/hooks` directory contains custom React hooks organized into two main categories: * **ahooks**: A comprehensive collection of React hooks (inspired by the ahooks library) * **external-hooks**: Additional custom hooks ## Directory Structure ``` src/hooks/ ├── ahooks/ │ ├── createDeepCompareEffect/ │ │ └── index.ts │ ├── createUpdateEffect/ │ │ └── index.ts │ ├── createUseStorageState/ │ │ └── index.ts │ ├── useAntdTable/ │ │ ├── index.tsx │ │ └── types.ts │ ├── useAsyncEffect/ │ │ └── index.ts │ ├── useBoolean/ │ │ └── index.ts │ ├── useClickAway/ │ │ └── index.ts │ ├── useControllableValue/ │ │ └── index.ts │ ├── useCookieState/ │ │ └── index.ts │ ├── useCountDown/ │ │ └── index.ts │ ├── useCounter/ │ │ └── index.ts │ ├── useCreation/ │ │ └── index.ts │ ├── useDebounce/ │ │ ├── debounceOptions.ts │ │ └── index.ts │ ├── useDebounceEffect/ │ │ └── index.ts │ ├── useDebounceFn/ │ │ └── index.ts │ ├── useDeepCompareEffect/ │ │ └── index.tsx │ ├── useDeepCompareLayoutEffect/ │ │ └── index.tsx │ ├── useDocumentVisibility/ │ │ └── index.ts │ ├── useDrag/ │ │ └── index.ts │ ├── useDrop/ │ │ └── index.ts │ ├── useDynamicList/ │ │ └── index.ts │ ├── useEventEmitter/ │ │ └── index.ts │ ├── useEventListener/ │ │ └── index.ts │ ├── useEventTarget/ │ │ └── index.ts │ ├── useExternal/ │ │ └── index.ts │ ├── useFavicon/ │ │ └── index.ts │ ├── useFocusWithin/ │ │ └── index.tsx │ ├── useFullscreen/ │ │ └── index.ts │ ├── useFusionTable/ │ │ ├── fusionAdapter.ts │ │ ├── index.tsx │ │ └── types.ts │ ├── useGetState/ │ │ └── index.ts │ ├── useHistoryTravel/ │ │ └── index.ts │ ├── useHover/ │ │ └── index.ts │ ├── useInfiniteScroll/ │ │ ├── index.tsx │ │ └── types.ts │ ├── useInterval/ │ │ └── index.ts │ ├── useInViewport/ │ │ └── index.ts │ ├── useIsomorphicLayoutEffect/ │ │ └── index.ts │ ├── useKeyPress/ │ │ └── index.ts │ ├── useLatest/ │ │ └── index.ts │ ├── useLocalStorageState/ │ │ └── index.ts │ ├── useLockFn/ │ │ └── index.ts │ ├── useLongPress/ │ │ └── index.ts │ ├── useMap/ │ │ └── index.ts │ ├── useMemoizedFn/ │ │ └── index.ts │ ├── useMount/ │ │ └── index.ts │ ├── useMouse/ │ │ └── index.ts │ ├── useMutationObserver/ │ │ └── index.ts │ ├── useNetwork/ │ │ └── index.ts │ ├── usePagination/ │ │ └── index.ts │ ├── usePrevious/ │ │ └── index.ts │ ├── useRafInterval/ │ │ └── index.ts │ ├── useRafState/ │ │ └── index.ts │ ├── useRafTimeout/ │ │ └── index.ts │ ├── useReactive/ │ │ └── index.ts │ ├── useRequest/ │ │ └── index.ts │ ├── useResetState/ │ │ └── index.ts │ ├── useResponsive/ │ │ └── index.ts │ ├── useSafeState/ │ │ └── index.ts │ ├── useScroll/ │ │ └── index.ts │ ├── useSelections/ │ │ └── index.ts │ ├── useSessionStorageState/ │ │ └── index.ts │ ├── useSet/ │ │ └── index.ts │ ├── useSetState/ │ │ └── index.ts │ ├── useSize/ │ │ └── index.ts │ ├── useTextSelection/ │ │ └── index.ts │ ├── useTheme/ │ │ └── index.ts │ ├── useThrottle/ │ │ └── index.ts │ ├── useThrottleEffect/ │ │ └── index.ts │ ├── useThrottleFn/ │ │ └── index.ts │ ├── useTimeout/ │ │ └── index.ts │ ├── useTitle/ │ │ └── index.ts │ ├── useToggle/ │ │ └── index.ts │ ├── useTrackedEffect/ │ │ └── index.ts │ ├── useUnmount/ │ │ └── index.ts │ ├── useUnmountedRef/ │ │ └── index.ts │ ├── useUpdate/ │ │ └── index.ts │ ├── useUpdateEffect/ │ │ └── index.ts │ ├── useUpdateLayoutEffect/ │ │ └── index.ts │ ├── useUrlState/ │ │ └── index.ts │ ├── useVirtualList/ │ │ └── index.ts │ ├── useWebSocket/ │ │ └── index.ts │ ├── useWhyDidYouUpdate/ │ │ └── index.ts │ └── utils/ │ └── (utility files) │ └── external-hooks/ ├── useCallbackEvent/ │ └── index.ts ├── useScrollLocker/ │ └── index.ts └── utils/ └── (utility files) ``` ## Hook Categories ### State Management Hooks * `useBoolean` - Manage boolean state * `useCounter` - Counter with increment/decrement * `useGetState` - Get latest state value * `useMap` - Manage Map data structure * `useReactive` - Create reactive state * `useResetState` - State with reset functionality * `useSafeState` - State that prevents memory leaks * `useSet` - Manage Set data structure * `useSetState` - Object state management * `useToggle` - Toggle between values ### Storage Hooks * `useCookieState` - Manage cookie state * `useLocalStorageState` - LocalStorage state * `useSessionStorageState` - SessionStorage state * `createUseStorageState` - Create storage hook factory ### Effect Hooks * `useAsyncEffect` - Async effect hook * `useDebounceEffect` - Debounced effect * `useDeepCompareEffect` - Effect with deep comparison * `useDeepCompareLayoutEffect` - Layout effect with deep comparison * `useThrottleEffect` - Throttled effect * `useTrackedEffect` - Track effect dependencies * `useUpdateEffect` - Effect that skips first render * `useUpdateLayoutEffect` - Layout effect that skips first render * `createDeepCompareEffect` - Create deep compare effect * `createUpdateEffect` - Create update effect factory ### Performance Hooks * `useDebounce` - Debounce value * `useDebounceFn` - Debounce function * `useThrottle` - Throttle value * `useThrottleFn` - Throttle function * `useMemoizedFn` - Memoize function * `useCreation` - Memoization like useMemo * `useLatest` - Get latest value without re-render * `usePrevious` - Get previous value ### DOM & Event Hooks * `useClickAway` - Detect clicks outside element * `useEventListener` - Add event listener * `useEventTarget` - Manage form inputs * `useFocusWithin` - Detect focus within element * `useHover` - Detect hover state * `useKeyPress` - Handle keyboard events * `useLongPress` - Detect long press * `useMouse` - Track mouse position * `useScroll` - Track scroll position * `useSize` - Monitor element size * `useTextSelection` - Track text selection ### Network & Request Hooks * `useRequest` - Data fetching and management * `useWebSocket` - WebSocket connection ### Lifecycle Hooks * `useMount` - Run on mount * `useUnmount` - Run on unmount * `useUnmountedRef` - Check if component is unmounted * `useUpdate` - Force component update ### Timer Hooks * `useCountDown` - Countdown timer * `useInterval` - setInterval hook * `useRafInterval` - requestAnimationFrame interval * `useRafTimeout` - requestAnimationFrame timeout * `useTimeout` - setTimeout hook ### Advanced Hooks * `useAntdTable` - Ant Design table integration * `useControllableValue` - Controlled/uncontrolled components * `useDrag` - Drag functionality * `useDrop` - Drop functionality * `useDynamicList` - Manage dynamic list * `useEventEmitter` - Event emitter pattern * `useExternal` - Load external resources * `useFavicon` - Manage favicon * `useFullscreen` - Fullscreen API * `useFusionTable` - Fusion table integration * `useHistoryTravel` - History state management * `useInfiniteScroll` - Infinite scroll * `useInViewport` - Element in viewport detection * `useLockFn` - Prevent concurrent function calls * `useMutationObserver` - MutationObserver API * `useNetwork` - Network status * `usePagination` - Pagination logic * `useResponsive` - Responsive breakpoints * `useSelections` - Selection management * `useTitle` - Document title * `useUrlState` - Sync state with URL * `useVirtualList` - Virtual list rendering * `useWhyDidYouUpdate` - Debug re-renders ### Layout Hooks * `useDocumentVisibility` - Document visibility state * `useIsomorphicLayoutEffect` - Cross-platform useLayoutEffect * `useRafState` - State with requestAnimationFrame ### External Hooks * `useCallbackEvent` - Custom callback event handling * `useScrollLocker` - Lock/unlock scroll ## Usage Import hooks directly from their directories: ```typescript import { useBoolean } from '@/hooks/ahooks/useBoolean'; import { useCallbackEvent } from '@/hooks/external-hooks/useCallbackEvent'; ``` ## Notes * Most hooks follow the pattern of one hook per directory * Each hook has its main implementation in `index.ts` or `index.tsx` * Some hooks have additional type definitions in `types.ts` files * Utility functions are stored in `utils/` directories # useAntdTable (/docs/useAntdTable) ## Overview `useAntdTable` is implemented based on `useRequest` and encapsulates the commonly used [Ant Design Form](https://ant.design/components/form/) and [Ant Design Table](https://ant.design/components/table/) data binding logic, and supports both antd v3 and v4. [Documentation and Examples](https://ahooks.js.org/hooks/use-antdtable) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useAntdTable.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useAntdTable.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useAntdTable.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useAntdTable.json ``` `useAntdTable` is implemented based on `useRequest` and encapsulates the commonly used [Ant Design Form](https://ant.design/components/form/) and [Ant Design Table](https://ant.design/components/table/) data binding logic, and supports both antd v3 and v4. Before using it, you need to understand a few points that are different from `useRequest`: 1. `service` receives two parameters, the first parameter is the paging data `{ current, pageSize, sorter, filters, extra }`, and the second parameter is the form data. 2. The data structure returned by `service` must be `{ total: number, list: Item[] }`. 3. Additional `tableProps` and `search` fields will be returned to manage tables and forms. 4. When `refreshDeps` changes, it will reset `current` to the first page and re-initiate the request. ## Examples The following demos are for antd v4. For v3, please refer to: [https://ahooks-v2.js.org/hooks/table/use-antd-table](https://ahooks-v2.js.org/hooks/table/use-antd-table) ### Table management `useAntdTable` will automatically manage the pagination data of `Table`, you only need to pass the returned `tableProps` to the `Table` component. ```tsx | pure ```
```tsx import { Table } from 'antd'; import React from 'react'; import { useAntdTable } from 'ahooks'; interface Item { name: { last: string; }; email: string; phone: string; gender: 'male' | 'female'; } interface Result { total: number; list: Item[]; } const getTableData = ({ current, pageSize }): Promise => { const query = `page=${current}&size=${pageSize}`; return fetch(`https://randomuser.me/api?results=55&${query}`) .then((res) => res.json()) .then((res) => ({ total: res.info.results, list: res.results, })); }; export default () => { const { tableProps } = useAntdTable(getTableData); const columns = [ { title: 'name', dataIndex: ['name', 'last'], }, { title: 'email', dataIndex: 'email', }, { title: 'phone', dataIndex: 'phone', }, { title: 'gender', dataIndex: 'gender', }, ]; return
; }; ``` ### Form and Table data binding When `useAntdTable` receives the `form` instance, it will return a search object to handle form related events. * `search.type` supports switching between `simple` and `advance` * `search.changeType`, switch form type * `search.submit` submit form * `search.reset` reset the current form In the following example, you can try out the data binding between form and table. ```tsx import React from 'react'; import { Button, Col, Form, Input, Row, Table, Select } from 'antd'; import { useAntdTable } from 'ahooks'; import ReactJson from 'react-json-view'; const { Option } = Select; interface Item { name: { last: string; }; email: string; phone: string; gender: 'male' | 'female'; } interface Result { total: number; list: Item[]; } const getTableData = ({ current, pageSize }, formData: Object): Promise => { let query = `page=${current}&size=${pageSize}`; Object.entries(formData).forEach(([key, value]) => { if (value) { query += `&${key}=${value}`; } }); return fetch(`https://randomuser.me/api?results=55&${query}`) .then((res) => res.json()) .then((res) => ({ total: res.info.results, list: res.results, })); }; export default () => { const [form] = Form.useForm(); const { tableProps, search, params } = useAntdTable(getTableData, { defaultPageSize: 5, form, }); const { type, changeType, submit, reset } = search; const columns = [ { title: 'name', dataIndex: ['name', 'last'], }, { title: 'email', dataIndex: 'email', }, { title: 'phone', dataIndex: 'phone', }, { title: 'gender', dataIndex: 'gender', }, ]; const advanceSearchForm = (
); const searchForm = (
); return (
{type === 'simple' ? searchForm : advanceSearchForm}

Current Table:

Current Form:

); }; ``` ### Default Params `useAntdTable` sets the initial value through `defaultParams`, `defaultParams` is an array, the first item is paging related parameters, and the second item is form related data. If there is a second value, we will initialize the form for you! It should be noted that the initial form data can be filled with all the form data of `simple` and `advance`, and we will help you select the form data of the currently activated type. The following example sets paging data and form data during initialization. ```tsx import React from 'react'; import { Button, Col, Form, Input, Row, Table, Select } from 'antd'; import { useAntdTable } from 'ahooks'; import ReactJson from 'react-json-view'; const { Option } = Select; interface Item { name: { last: string; }; email: string; phone: string; gender: 'male' | 'female'; } interface Result { total: number; list: Item[]; } const getTableData = ({ current, pageSize }, formData: Object): Promise => { let query = `page=${current}&size=${pageSize}`; Object.entries(formData).forEach(([key, value]) => { if (value) { query += `&${key}=${value}`; } }); return fetch(`https://randomuser.me/api?results=55&${query}`) .then((res) => res.json()) .then((res) => ({ total: res.info.results, list: res.results, })); }; export default () => { const [form] = Form.useForm(); const { loading, tableProps, search, params } = useAntdTable(getTableData, { form, defaultParams: [ { current: 2, pageSize: 5 }, { name: 'hello', email: 'abc@gmail.com', gender: 'female' }, ], defaultType: 'advance', }); const { type, changeType, submit, reset } = search; const columns = [ { title: 'name', dataIndex: ['name', 'last'], }, { title: 'email', dataIndex: 'email', }, { title: 'phone', dataIndex: 'phone', }, { title: 'gender', dataIndex: 'gender', }, ]; const advanceSearchForm = (
); const searchForm = (
); return (
{type === 'simple' ? searchForm : advanceSearchForm}

Current Table:

Current Form:

); }; ``` ### Form Validation Before the form is submitted, we will call `form.validateFields` to validate the form data. If the verification fails, the request will not be initiated. ```tsx import { Form, Input, Select, Table } from 'antd'; import React from 'react'; import { useAntdTable } from 'ahooks'; import ReactJson from 'react-json-view'; const { Option } = Select; interface Item { name: { last: string; }; email: string; phone: string; gender: 'male' | 'female'; } interface Result { total: number; list: Item[]; } const getTableData = ({ current, pageSize }, formData: Object): Promise => { let query = `page=${current}&size=${pageSize}`; Object.entries(formData).forEach(([key, value]) => { if (value) { query += `&${key}=${value}`; } }); return fetch(`https://randomuser.me/api?results=55&${query}`) .then((res) => res.json()) .then((res) => ({ total: res.info.results, list: res.results, })); }; export default () => { const [form] = Form.useForm(); const { tableProps, search, params } = useAntdTable(getTableData, { defaultPageSize: 5, form, }); const { submit } = search; const columns = [ { title: 'name', dataIndex: ['name', 'last'], }, { title: 'email', dataIndex: 'email', }, { title: 'phone', dataIndex: 'phone', }, { title: 'gender', dataIndex: 'gender', }, ]; const searchForm = (
); return (
{searchForm}

Current Table:

Current Form:

); }; ``` ### Data Caching By setting `cacheKey`, we can apply the data caching for the `Form` and `Table`. ```tsx import React, { useState } from 'react'; import { Button, Col, Form, Input, Row, Table, Select } from 'antd'; import { useAntdTable, clearCache } from 'ahooks'; import ReactJson from 'react-json-view'; const { Option } = Select; interface Item { name: { last: string; }; email: string; phone: string; gender: 'male' | 'female'; } interface Result { total: number; list: Item[]; } const getTableData = ( { current, pageSize, sorter, filters, extra }, formData: Object, ): Promise => { console.log(sorter, filters, extra); let query = `page=${current}&size=${pageSize}`; Object.entries(formData).forEach(([key, value]) => { if (value) { query += `&${key}=${value}`; } }); return fetch(`https://randomuser.me/api?results=55&${query}`) .then((res) => res.json()) .then((res) => ({ total: res.info.results, list: res.results, })); }; const UserList = () => { const [form] = Form.useForm(); const { tableProps, search, params } = useAntdTable(getTableData, { defaultPageSize: 5, form, cacheKey: 'useAntdTableCache', }); const { sorter = {}, filters = {} } = params[0] || ({} as any); const { type, changeType, submit, reset } = search; const columns = [ { title: 'name', dataIndex: ['name', 'last'], }, { title: 'email', dataIndex: 'email', }, { title: 'phone', dataIndex: 'phone', sorter: true, sortOrder: sorter.field === 'phone' && sorter.order, }, { title: 'gender', dataIndex: 'gender', filters: [ { text: 'male', value: 'male' }, { text: 'female', value: 'female' }, ], filteredValue: filters.gender, }, ]; const advanceSearchForm = (
); const searchForm = (
); return (
{type === 'simple' ? searchForm : advanceSearchForm}

Current Table:

Current Form:

); }; const Demo = () => { const [show, setShow] = useState(true); return (
{show && }
); }; export default Demo; ``` ## API All parameters and returned results of `useRequest` are applicable to `useAntdTable`, so we won't repeat them here. ```typescript type Data = { total: number; list: any[] }; type Params = [{ current: number; pageSize: number, filters?: any, sorter?: any, extra?: any }, { [key: string]: any }]; const { ..., tableProps: { dataSource: TData['list']; loading: boolean; onChange: ( pagination: any, filters?: any, sorter?: any, extra?: any, ) => void; pagination: { current: number; pageSize: number; total: number; }; }; search: { type: 'simple' | 'advance'; changeType: () => void; submit: () => void; reset: () => void; }; } = useAntdTable( service: (...args: TParams) => Promise, { ..., form?: any; defaultType?: 'simple' | 'advance'; defaultParams?: TParams, defaultPageSize?: number; refreshDeps?: any[]; } ); ``` ### Result | Property | Description | Type | | ----------------- | ------------------------------------------ | --------------------- | | tableProps | The data required by the `Table` component | - | | search.type | Current form type | `simple` \| `advance` | | search.changeType | Switch form type | `() => void` | | search.submit | Submit form | `() => void` | | search.reset | Reset the current form | `() => void` | ### Params | Property | Description | Type | Default | | --------------- | ------------------------------------------------------------------------------------------ | ------------------------ | -------- | | form | `Form` instance | - | - | | defaultType | Default form type | `simple` \| `advance` | `simple` | | defaultParams | Default parameters, the first item is paging data, the second item is form data | `[pagination, formData]` | - | | defaultPageSize | Default page size | `number` | `10` | | refreshDeps | Changes in `refreshDeps` will reset current to the first page and re-initiate the request. | `React.DependencyList` | `[]` | # useAsyncEffect (/docs/useAsyncEffect) ## Overview useEffect support async function. [Documentation and Examples](https://ahooks.js.org/hooks/use-asynceffect) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useAsyncEffect.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useAsyncEffect.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useAsyncEffect.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useAsyncEffect.json ``` useEffect support async function. ## 代码演示 ### Default usage { return new Promise((resolve) => { setTimeout(() => { resolve(true); }, 3000); }); } const Example = () => { const [pass, setPass] = useState(); useAsyncEffect(async () => { setPass(await mockCheck()); }, []); return (
{pass === undefined && 'Checking...'} {pass === true && 'Check passed.'}
); }; export default Example;`} /> ### Break off { return new Promise((resolve) => { setTimeout(() => { resolve(val.length > 0); }, 1000); }); } const Example = () => { const [value, setValue] = useState(''); const [pass, setPass] = useState(); useAsyncEffect( async function* () { setPass(undefined); const result = await mockCheck(value); yield; // Check whether the effect is still valid, if it is has been cleaned up, stop at here. setPass(result); }, [value], ); return (
{ setValue(e.target.value); }} />

{pass === null && 'Checking...'} {pass === false && 'Check failed.'} {pass === true && 'Check passed.'}

); }; export default Example;`} /> ## API ```typescript function useAsyncEffect( effect: () => AsyncGenerator | Promise, deps: DependencyList ); ``` # useBoolean (/docs/useBoolean) ## Overview A hook that elegantly manages boolean state. [Documentation and Examples](https://ahooks.js.org/hooks/use-boolean) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useBoolean.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useBoolean.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useBoolean.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useBoolean.json ``` A hook that elegantly manages boolean state. ## Examples ### Default usage { const [state, { toggle, setTrue, setFalse }] = useBoolean(true); return (

Effects:{JSON.stringify(state)}

); }; export default Example;`} /> ## API ```typescript const [state, { toggle, set, setTrue, setFalse }] = useBoolean( defaultValue?: boolean, ); ``` ### Params | Property | Description | Type | Default | | ------------ | ----------------------------------------- | --------- | ------- | | defaultValue | The default value of the state. Optional. | `boolean` | `false` | ### Result | Property | Description | Type | | -------- | -------------------------------------- | --------- | | state | Current value | `boolean` | | actions | A set of methods to update state value | `Actions` | ### Actions | Property | Description | Type | | -------- | -------------------- | -------------------------- | | toggle | Toggle state | `() => void` | | set | Set state | `(value: boolean) => void` | | setTrue | Set state to `true` | `() => void` | | setFalse | Set state to `false` | `() => void` | # useClickAway (/docs/useClickAway) ## Overview Listen for click events outside the target element. [Documentation and Examples](https://ahooks.js.org/hooks/use-clickaway) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useClickAway.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useClickAway.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useClickAway.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useClickAway.json ``` Listen for click events outside the target element. ## Examples ### Default usage { const [counter, setCounter] = useState(0); const ref = useRef(null); useClickAway(() => { setCounter((s) => s + 1); }, ref); return (

counter: {counter}

); }; export default Example;`} /> ### Custom DOM { const [counter, setCounter] = useState(0); useClickAway( () => { setCounter((s) => s + 1); }, () => document.getElementById('use-click-away-button'), ); return (

counter: {counter}

); }; export default Example;`} /> ### Support multiple DOM { const [counter, setCounter] = useState(0); const ref1 = useRef(null); const ref2 = useRef(null); useClickAway(() => { setCounter((s) => s + 1); }, [ref1, ref2]); return (

counter: {counter}

); }; export default Example;`} /> ### Listen for other events * By setting eventName, you can specify the event to be listened, Try click the right mouse. { const [counter, setCounter] = useState(0); const ref = useRef(null); useClickAway( () => { setCounter((s) => s + 1); }, ref, 'contextmenu', ); return (

counter: {counter}

); }; export default Example;`} /> ### Support multiple events { const [counter, setCounter] = useState(0); const ref = useRef(null); useClickAway( () => { setCounter((s) => s + 1); }, ref, ['click', 'contextmenu'], ); return (

counter: {counter}

); }; export default Example;`} /> ### Support shadow DOM { const [counter, setCounter] = useState(0); const ref = useRef(null); useClickAway( () => { setCounter((s) => s + 1); }, ref, ['click', 'contextmenu'], ); return (

counter: {counter}

); }; export default Example;`} /> ## API ```typescript type Target = Element | (() => Element) | React.MutableRefObject; type DocumentEventKey = keyof DocumentEventMap; useClickAway( onClickAway: (event: T) => void, target: Target | Target[], eventName?: DocumentEventKey | DocumentEventKey[] ); ``` ### Params | Property | Description | Type | Default | | ----------- | ---------------------------------------------- | ------------------------------------------ | ------- | | onClickAway | Trigger Function | `(event: T) => void` | - | | target | DOM elements or Ref or Function, support array | `Target` \| `Target[]` | - | | eventName | Set the event to be listened, support array | `DocumentEventKey` \| `DocumentEventKey[]` | `click` | # useControllableValue (/docs/useControllableValue) ## Overview In some components, we need the state to be managed by itself or controlled by it's parent. `useControllableValue` is a Hook that helps you manage this kind of state. [Documentation and Examples](https://ahooks.js.org/hooks/use-controllablevalue) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useControllableValue.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useControllableValue.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useControllableValue.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useControllableValue.json ``` In some components, we need the state to be managed by itself or controlled by it's parent. `useControllableValue` is a Hook that helps you manage this kind of state. ## Examples ### Uncontrolled component { const [state, setState] = useControllableValue(props, { defaultValue: '', }); return ( <> setState(e.target.value)} style={{ width: 300 }} /> ); }; export default Example;`} /> ### Controlled component { const [state, setState] = useControllableValue(props); return setState(e.target.value)} style={{ width: 300 }} />; }; const Example = () => { const [state, setState] = useState(''); const clear = () => { setState(''); }; return ( <> ); }; export default Example;`} /> ### No value, have onChange component { const [state, setState] = useControllableValue(props); return ( { setState(e.target.value); }} style={{ width: 300 }} /> ); }; const Example = () => { const [state, setState] = useState(0); return ( <>
state:{state}
); }; export default Example;`} /> ## API ```typescript const [state, setState] = useControllableValue(props: Record, options?: Options); ``` ### Result | Property | Description | Type | | -------- | ----------- | --------------------------------------------------- | | state | State | - | | setState | Set state | `(value: any \| ((prevState: any) => any)) => void` | ### Params | Property | Description | Type | Default | | -------- | ---------------------- | --------------------- | ------- | | props | Component props | `Record` | - | | options | Optional configuration | `Options` | - | ### Options | Property | Description | Type | Default | | -------------------- | ------------------------------------------------------------------------------- | -------- | -------------- | | defaultValue | The default value, will be overridden by `props.defaultValue` and `props.value` | - | - | | defaultValuePropName | Custom defaultValue attribute name | `string` | `defaultValue` | | valuePropName | Custom value attribute name | `string` | `value` | | trigger | Custom trigger attribute name | `string` | `onChange` | # useCookieState (/docs/useCookieState) ## Overview A Hook that store state into Cookie. [Documentation and Examples](https://ahooks.js.org/hooks/use-cookiestate) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCookieState.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCookieState.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCookieState.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCookieState.json ``` A Hook that store state into Cookie. ## Examples ### Store state into Cookie { const [message, setMessage] = useCookieState('useCookieStateString'); return ( setMessage(e.target.value)} style={{ width: 300 }} /> ); }; export default Example;`} /> ### SetState can receive function { const [value, setValue] = useCookieState('useCookieStateUpdater', { defaultValue: '0', }); return ( <>

{value}

); }; export default Example;`} /> ### Use the option property to configure Cookie { const [value, setValue] = useCookieState('useCookieStateOptions', { defaultValue: '0', path: '/', expires: (() => new Date(+new Date() + 10000))(), }); return ( <>

{value}

); }; export default Example;`} /> ## API ```typescript type State = string | undefined; type SetState = ( newValue?: State | ((prevState?: State) => State), options?: Cookies.CookieAttributes, ) => void; const [state, setState]: [State, SetState] = useCookieState( cookieKey: string, options?: Options, ); ``` If you want to delete this record from document.cookie, use `setState()` or `setState(undefined)`. ### Params | Property | Description | Type | Default | | --------- | ------------------------------ | --------- | ------- | | cookieKey | The key of Cookie | `string` | - | | options | Optional. Cookie configuration | `Options` | - | ### Result | Property | Description | Type | | -------- | ------------------- | ----------------------- | | state | Local Cookie value | `string` \| `undefined` | | setState | Update Cookie value | `SetState` | setState can update cookie options, which will be merged with the options set by `useCookieState`. `const targetOptions = { ...options, ...updateOptions }` ### Options | Property | Description | Type | Default | | ------------ | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------- | ----------- | | defaultValue | Optional. Default value, but not store to Cookie | `string` \| `undefined` \| `(() => (string \| undefined))` | `undefined` | | expires | Optional. Set Cookie expiration time | `number` \| `Date` | - | | path | Optional. Specify available paths | `string` | `/` | | domain | Optional. Specify available domain. Default creation domain | `string` | - | | secure | Optional. Specify whether the Cookie can only be transmitted over secure protocol as https | `boolean` | `false` | | sameSite | Optional. Specify whether the browser can send this Cookie along with cross-site requests | `strict` \| `lax` \| `none` | - | Options is same as [js-cookie attributes](https://github.com/js-cookie/js-cookie#cookie-attributes). # useCountDown (/docs/useCountDown) ## Overview A hook for manage countdown. [Documentation and Examples](https://ahooks.js.org/hooks/use-countdown) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCountDown.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCountDown.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCountDown.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCountDown.json ``` A hook for manage countdown. ## Countdown to target time { const [, formattedRes] = useCountDown({ targetDate: \`\${new Date().getFullYear()}-12-31 23:59:59\`, }); const { days, hours, minutes, seconds, milliseconds } = formattedRes; return (

There are {days} days {hours} hours {minutes} minutes {seconds} seconds {milliseconds}{' '} milliseconds until {new Date().getFullYear()}-12-31 23:59:59

); }; export default Example;`} /> ## Dynamic config { const [targetDate, setTargetDate] = useState(); const [countdown] = useCountDown({ targetDate, onEnd: () => { alert('End of the time'); }, }); return ( <> ); }; export default Example;`} /> ## Config leftTime { const [countdown] = useCountDown({ leftTime: 60 * 1000 }); return

{countdown}

; }; export default Example;`} /> ## API ```typescript type TDate = Date | number | string | undefined; interface FormattedRes { days: number; hours: number; minutes: number; seconds: number; milliseconds: number; } const [countdown, formattedRes] = useCountDown( { leftTime, targetDate, interval, onEnd } ); ``` **Remark** The precision of useCountDown is milliseconds, which may cause the following problems * Even if the interval time is set to 1000ms, the update interval of useCountDown may not be exactly 1000ms, but around it. * In the second demo, countdown is generally 499x milliseconds at the beginning due to the execution delay of the program. If you only need to be accurate to the second, you can use it like this `Math.round(countdown / 1000)`. If both `leftTime` and `targetDate` are passed, the `targetDate` is ignored, the `leftTime` is dominant. ### Params | Property | Description | Type | Default | | ---------- | -------------------------------------------- | ------------ | ------- | | leftTime | The rest of time, in milliseconds | `number` | - | | targetDate | Target time | `TDate` | - | | interval | Time interval between ticks, in milliseconds | `number` | `1000` | | onEnd | Function to call when countdown completes | `() => void` | - | ### Return | Params | Description | Type | | --------------- | ---------------------------------------- | -------------- | | countdown | Timestamp to targetDate, in milliseconds | `number` | | formattedResult | Formatted countdown | `FormattedRes` | ## Remark `leftTime`、`targetDate`、`interval`、`onEnd` support dynamic change. # useCounter (/docs/useCounter) ## Overview A hook that manage counter. [Documentation and Examples](https://ahooks.js.org/hooks/use-counter) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCounter.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCounter.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCounter.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCounter.json ``` A hook that manage counter. ## Examples ### Default usage { const [current, { inc, dec, set, reset }] = useCounter(100, { min: 1, max: 10 }); return (

{current} [max: 10; min: 1;]

); }; export default Example;`} /> ## API ```typescript const [current, { inc, dec, set, reset }] = useCounter(initialValue, { min, max }); ``` ### Result | Property | Description | Type | | -------- | ------------------------------------ | ------------------------------------------------------ | | current | Current value | `number` | | inc | Increment, default delta is 1 | `(delta?: number) => void` | | dec | Decrement, default delta is 1 | `(delta?: number) => void` | | set | Set current value | `(value: number` \| `((c: number) => number)) => void` | | reset | Reset current value to initial value | `() => void` | ### Params | Property | Description | Type | Default | | ------------ | ------------- | -------- | ------- | | initialValue | Initial count | `number` | `0` | | min | Min count | `number` | - | | max | Max count | `number` | - | # useCreation (/docs/useCreation) ## Overview `useCreation` is the replacement for `useMemo` or `useRef`. [Documentation and Examples](https://ahooks.js.org/hooks/use-creation) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCreation.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCreation.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCreation.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCreation.json ``` `useCreation` is the replacement for `useMemo` or `useRef`. `useMemo` can't guarantee the memoized value will not be recalculated, while `useCreation` can guarantee that. As the the official document of React.js says: > **You may rely on useMemo as a performance optimization, not as a semantic guarantee.** In the future, React may choose to “forget” some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components. Write your code so that it still works without `useMemo` — and then add it to optimize performance. And similar to `useRef`, you can use `useCreation` to create some constants. But `useCreation` can avoid performance hazards. ```javascript const a = useRef(new Subject()); // A new Subject instance is created in every render. const b = useCreation(() => new Subject(), []); // By using factory function, Subject is only instantiated once. ``` ## Examples ### Default usage { const foo = useCreation(() => new Foo(), []); const [, setFlag] = useState({}); return ( <>

{foo.data}

); }; export default Example;`} /> ## API ```javascript function useCreation(factory: () => T, deps: any[]): T; ``` ### Params | Property | Description | Type | Default | | -------- | ---------------------------------------- | ----------- | ------- | | factory | A function used for creating the object. | `() => any` | - | | deps | The dependencies list. | `any[]` | - | # useDebounce (/docs/useDebounce) ## Overview A hook that deal with the debounced value. [Documentation and Examples](https://ahooks.js.org/hooks/use-debounce) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDebounce.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDebounce.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDebounce.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDebounce.json ``` A hook that deal with the debounced value. ## Examples ### Default usage { const [value, setValue] = useState(); const debouncedValue = useDebounce(value, { wait: 500 }); return (
setValue(e.target.value)} placeholder="Typed value" style={{ width: 280 }} />

DebouncedValue: {debouncedValue}

); }; export default Example;`} /> ## API ```typescript const debouncedValue = useDebounce( value: any, options?: Options ); ``` ### Params | Property | Description | Type | Default | | -------- | ---------------------------------- | --------- | ------- | | value | The value to debounce. | `any` | - | | options | Config for the debounce behaviors. | `Options` | - | ### Options | Property | Description | Type | Default | | -------- | ------------------------------------------------------------------- | --------- | ------- | | wait | The number of milliseconds to delay. | `number` | `1000` | | leading | Specify invoking on the leading edge of the timeout. | `boolean` | `false` | | trailing | Specify invoking on the trailing edge of the timeout. | `boolean` | `true` | | maxWait | The maximum time func is allowed to be delayed before it’s invoked. | `number` | - | # useDebounceEffect (/docs/useDebounceEffect) ## Overview Debounce your `useEffect`. [Documentation and Examples](https://ahooks.js.org/hooks/use-debounceeffect) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDebounceEffect.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDebounceEffect.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDebounceEffect.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDebounceEffect.json ``` Debounce your `useEffect`. ## Examples ### Default usage { const [value, setValue] = useState('hello'); const [records, setRecords] = useState([]); useDebounceEffect( () => { setRecords((val) => [...val, value]); }, [value], { wait: 1000, }, ); return (
setValue(e.target.value)} placeholder="Typed value" style={{ width: 280 }} />

    {records.map((record, index) => (
  • {record}
  • ))}

); }; export default Example;`} /> ## API ```typescript useDebounceEffect( effect: EffectCallback, deps?: DependencyList, options?: Options ); ``` ### Params | Property | Description | Type | Default | | -------- | ----------------------------------------------------------------------------- | ---------------- | ------- | | effect | The effect callback. | `EffectCallback` | - | | deps | The dependencies list. | `DependencyList` | - | | options | Config for the debounce behaviors. See the Options section below for details. | `Options` | - | ### Options | Property | Description | Type | Default | | -------- | ------------------------------------------------------------------- | --------- | ------- | | wait | The number of milliseconds to wait. | `number` | `1000` | | leading | Specify invoking on the leading edge of the timeout. | `boolean` | `false` | | trailing | Specify invoking on the trailing edge of the timeout. | `boolean` | `true` | | maxWait | The maximum time func is allowed to be delayed before it’s invoked. | `number` | - | # useDebounceFn (/docs/useDebounceFn) ## Overview A hook that deal with the debounced function. [Documentation and Examples](https://ahooks.js.org/hooks/use-debouncefn) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDebounceFn.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDebounceFn.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDebounceFn.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDebounceFn.json ``` A hook that deal with the debounced function. ## Examples ### Default usage { const [value, setValue] = useState(0); const { run } = useDebounceFn( () => { setValue(value + 1); }, { wait: 500, }, ); return (

Clicked count: {value}

); }; export default Example;`} /> ## API ```typescript const { run, cancel, flush } = useDebounceFn( fn: (...args: any[]) => any, options?: Options ); ``` ### Params | Property | Description | Type | Default | | -------- | ---------------------------------- | ------------------------- | ------- | | fn | The function to debounce. | `(...args: any[]) => any` | - | | options | Config for the debounce behaviors. | `Options` | - | ### Options | Property | Description | Type | Default | | -------- | ------------------------------------------------------------------- | --------- | ------- | | wait | The number of milliseconds to delay. | `number` | `1000` | | leading | Specify invoking on the leading edge of the timeout. | `boolean` | `false` | | trailing | Specify invoking on the trailing edge of the timeout. | `boolean` | `true` | | maxWait | The maximum time func is allowed to be delayed before it’s invoked. | `number` | - | ### Result | Property | Description | Type | | -------- | ------------------------------------------------------ | ------------------------- | | run | invoke and pass parameters to fn. | `(...args: any[]) => any` | | cancel | Cancel the invocation of currently debounced function. | `() => void` | | flush | Immediately invoke currently debounced function. | `() => void` | # useDeepCompareEffect (/docs/useDeepCompareEffect) ## Overview Usage is the same as `useEffect`, but deps are compared with [react-fast-compare](https://www.npmjs.com/package/react-fast-compare). [Documentation and Examples](https://ahooks.js.org/hooks/use-deepcompareeffect) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDeepCompareEffect.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDeepCompareEffect.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDeepCompareEffect.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDeepCompareEffect.json ``` Usage is the same as `useEffect`, but deps are compared with [react-fast-compare](https://www.npmjs.com/package/react-fast-compare). ## Examples ### Default usage { const [count, setCount] = useState(0); const effectCountRef = useRef(0); const deepCompareCountRef = useRef(0); useEffect(() => { effectCountRef.current += 1; }, [{}]); useDeepCompareEffect(() => { deepCompareCountRef.current += 1; return () => { // do something }; }, [{}]); return (

effectCount: {effectCountRef.current}

deepCompareCount: {deepCompareCountRef.current}

); }; export default Example;`} /> ## API ```typescript useDeepCompareEffect( effect: React.EffectCallback, deps: React.DependencyList ); ``` # useDeepCompareLayoutEffect (/docs/useDeepCompareLayoutEffect) ## Overview Usage is the same as `useLayoutEffect`, but deps are compared with [react-fast-compare](https://www.npmjs.com/package/react-fast-compare). [Documentation and Examples](https://ahooks.js.org/hooks/use-deepcomparelayouteffect) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDeepCompareLayoutEffect.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDeepCompareLayoutEffect.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDeepCompareLayoutEffect.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDeepCompareLayoutEffect.json ``` Usage is the same as `useLayoutEffect`, but deps are compared with [react-fast-compare](https://www.npmjs.com/package/react-fast-compare). ## Examples ### Default usage { const [count, setCount] = useState(0); const effectCountRef = useRef(0); const deepCompareCountRef = useRef(0); useLayoutEffect(() => { effectCountRef.current += 1; }, [{}]); useDeepCompareLayoutEffect(() => { deepCompareCountRef.current += 1; return () => { // do something }; }, [{}]); return (

effectCount: {effectCountRef.current}

deepCompareCount: {deepCompareCountRef.current}

); }; export default Example;`} /> ## API ```typescript useDeepCompareLayoutEffect( effect: React.EffectCallback, deps: React.DependencyList ); ``` # useDocumentVisibility (/docs/useDocumentVisibility) ## Overview A Hook can tell if the page is visible, refer to [visibilityState API](https://developer.mozilla.org/docs/Web/API/Document/visibilityState) [Documentation and Examples](https://ahooks.js.org/hooks/use-documentvisibility) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDocumentVisibility.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDocumentVisibility.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDocumentVisibility.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDocumentVisibility.json ``` A Hook can tell if the page is visible, refer to [visibilityState API](https://developer.mozilla.org/docs/Web/API/Document/visibilityState) ## Examples { const documentVisibility = useDocumentVisibility(); useEffect(() => { console.log(\`Current document visibility state: \${documentVisibility}\`); }, [documentVisibility]); return
Current document visibility state: {documentVisibility}
; }; export default Example;`} /> ## API ```typescript const documentVisibility = useDocumentVisibility(); ``` ### Result | Property | Description | Type | | ------------------ | ------------------------------- | -------------------------------------------------- | | documentVisibility | Whether the document is visible | `visible`\| `hidden` \| `prerender` \| `undefined` | # useDrag (/docs/useDrag) ## Overview A pair of hooks to help you manage data transfer between drag and drop [Documentation and Examples](https://ahooks.js.org/hooks/use-drop) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDrag.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDrag.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDrag.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDrag.json ``` ### Basic Usage { const dragRef = useRef(null); const [dragging, setDragging] = useState(false); useDrag(data, dragRef, { onDragStart: () => { setDragging(true); }, onDragEnd: () => { setDragging(false); }, }); return (
{dragging ? 'dragging' : \`box-\${data}\`}
); }; const Example = () => { const [isHovering, setIsHovering] = useState(false); const dropRef = useRef(null); useDrop(dropRef, { onText: (text, e) => { console.log(e); alert(\`'text: \${text}' dropped\`); }, onFiles: (files, e) => { console.log(e, files); alert(\`\${files.length} file dropped\`); }, onUri: (uri, e) => { console.log(e); alert(\`uri: \${uri} dropped\`); }, onDom: (content: string, e) => { alert(\`custom: \${content} dropped\`); }, onDragEnter: () => setIsHovering(true), onDragLeave: () => setIsHovering(false), }); return (
{isHovering ? 'release here' : 'drop here'}
{['1', '2', '3', '4', '5'].map((e) => ( ))}
); }; export default Example;`} /> ### Customize Image { const dragRef = useRef(null); useDrag('', dragRef, { dragImage: { image: 'https://upload.wikimedia.org/wikipedia/commons/8/8e/Nextjs-logo.svg', }, }); return (
drag me
); }; export default Example;`} /> ## API ### useDrag ```typescript useDrag( data: any, target: (() => Element) | Element | MutableRefObject, options?: DragOptions ); ``` #### Params | Property | Description | Type | Default | | -------- | ------------------ | ----------------------------------------------------------- | ------- | | data | Drag data | `any` | - | | target | DOM element or ref | `() => Element` \| `Element` \| `MutableRefObject` | - | | options | More config | `DragOptions` | - | #### DragOptions | Property | Description | Type | Default | | ----------- | ------------------------------------------------------------- | ------------------------------ | ------- | | onDragStart | On drag start callback | `(e: React.DragEvent) => void` | - | | onDragEnd | On drag end callback | `(e: React.DragEvent) => void` | - | | dragImage | Customize image that follow the mouse pointer during dragging | `DragImageOptions` | - | #### DragImageOptions | 参数 | 说明 | 类型 | 默认值 | | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | --- | | image | An image Element element to use for the drag feedback image. The image will typically be an [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img) element but it can also be a [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas) or any other visible element | `string \| Element` | - | | offsetX | the horizontal offset within the image | `number` | 0 | | offsetY | the vertical offset within the image | `number` | 0 | # useDrop (/docs/useDrop) ## Overview A pair of hooks to help you manage data transfer between drag and drop [Documentation and Examples](https://ahooks.js.org/hooks/use-drop) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDrop.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDrop.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDrop.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDrop.json ``` A pair of hooks to help you manage data transfer between drag and drop > useDrop can be used alone to accept file, text or uri dropping. > > useDrag should be used along with useDrop. > > Paste into the drop area will also be treated as content drop. ## Examples ### Basic Usage { const dragRef = useRef(null); const [dragging, setDragging] = useState(false); useDrag(data, dragRef, { onDragStart: () => { setDragging(true); }, onDragEnd: () => { setDragging(false); }, }); return (
{dragging ? 'dragging' : \`box-\${data}\`}
); }; const Example = () => { const [isHovering, setIsHovering] = useState(false); const dropRef = useRef(null); useDrop(dropRef, { onText: (text, e) => { console.log(e); alert(\`'text: \${text}' dropped\`); }, onFiles: (files, e) => { console.log(e, files); alert(\`\${files.length} file dropped\`); }, onUri: (uri, e) => { console.log(e); alert(\`uri: \${uri} dropped\`); }, onDom: (content: string, e) => { alert(\`custom: \${content} dropped\`); }, onDragEnter: () => setIsHovering(true), onDragLeave: () => setIsHovering(false), }); return (
{isHovering ? 'release here' : 'drop here'}
{['1', '2', '3', '4', '5'].map((e) => ( ))}
); }; export default Example;`} /> ### Customize Image { const dragRef = useRef(null); useDrag('', dragRef, { dragImage: { image: 'https://upload.wikimedia.org/wikipedia/commons/8/8e/Nextjs-logo.svg', }, }); return (
drag me
); }; export default Example;`} /> ## API ### useDrop ```typescript useDrop( target: (() => Element) | Element | MutableRefObject, options?: DropOptions ); ``` #### Params | Property | Description | Type | Default | | -------- | ------------------ | ----------------------------------------------------------- | ------- | | target | DOM element or ref | `() => Element` \| `Element` \| `MutableRefObject` | - | | options | More config | `DropOptions` | - | #### DropOptions | Property | Description | Type | Default | | ----------- | ------------------------------------------- | --------------------------------------------- | ------- | | onText | The callback when text is dropped or pasted | `(text: string, e: React.DragEvent) => void` | - | | onFiles | The callback when file is dropped or pasted | `(files: File[], e: React.DragEvent) => void` | - | | onUri | The callback when uri is dropped or pasted | `(text: string, e: React.DragEvent) => void` | - | | onDom | The callback when DOM is dropped or pasted | `(content: any, e: React.DragEvent) => void` | - | | onDrop | The callback when any is dropped | `(e: React.DragEvent) => void` | - | | onPaste | The callback when any is pasted | `(e: React.DragEvent) => void` | - | | onDragEnter | On drag enter callback | `(e: React.DragEvent) => void` | - | | onDragOver | On drag over callback | `(e: React.DragEvent) => void` | - | | onDragLeave | On drag leave callback | `(e: React.DragEvent) => void` | - | # useDynamicList (/docs/useDynamicList) ## Overview A hook that helps you manage dynamic list and generate unique key for each item. [Documentation and Examples](https://ahooks.js.org/hooks/use-dynamiclist) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDynamicList.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDynamicList.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDynamicList.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useDynamicList.json ``` A hook that helps you manage dynamic list and generate unique key for each item. ## Examples ### Basic usage ```tsx import useDynamicList from '@/src/hooks/ahooks/useDynamicList'; import { MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons'; import { Button, Input, Space } from 'antd'; import React from 'react'; const Example = () => { const { list, remove, batchRemove, getKey, insert, replace } = useDynamicList(['David', 'Jack']); const listIndexes = list.map((item, index) => index); const Row = (index: number, item: any) => (
replace(index, e.target.value)} value={item} /> {list.length > 1 && ( { remove(index); }} /> )} { insert(index + 1, ''); }} />
); return ( <> {list.map((ele, index) => Row(index, ele))}
{JSON.stringify([list])}
); }; export default Example; ``` ### Using with antd Form ```tsx import { MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons'; import { useDynamicList } from 'ahooks'; import { Button, Form, Input } from 'antd'; import React, { useEffect, useState } from 'react'; const DynamicInputs = ({ value = [], onChange, }: { value?: string[]; onChange?: (value: string[]) => void; }) => { const { list, remove, getKey, insert, replace, resetList } = useDynamicList(value); useEffect(() => { // If value change manual, reset list if (value !== list) { resetList(value); } }, [value]); useEffect(() => { onChange?.(list); }, [list]); const Row = (index: number, item: any) => (
replace(index, e.target.value)} value={item} /> {list.length > 1 && ( { remove(index); }} /> )} { insert(index + 1, ''); }} />
); return <>{list.map((ele, index) => Row(index, ele))}; }; export default () => { const [form] = Form.useForm(); const [result, setResult] = useState(''); return ( <>

{result}

); }; ``` ### Another way of writing used in antd Form ```tsx import React, { useState } from 'react'; import { Form, Button, Input } from 'antd'; import { MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons'; import { useDynamicList } from 'ahooks'; export default () => { const { list, remove, getKey, insert, resetList, sortList } = useDynamicList(['David', 'Jack']); const [form] = Form.useForm(); const [result, setResult] = useState(''); const Row = (index: number, item: any) => (
{list.length > 1 && ( { remove(index); }} /> )} { insert(index + 1, ''); }} />
); return ( <>
{list.map((ele, index) => Row(index, ele))}
{result}
); }; ``` ### Draggable dynamic table ```tsx import { DragOutlined } from '@ant-design/icons'; import { Button, Form, Input, Table } from 'antd'; import React, { useState } from 'react'; import ReactDragListView from 'react-drag-listview'; import { useDynamicList } from 'ahooks'; interface Item { name?: string; age?: string; memo?: string; } export default () => { const { list, remove, getKey, move, push, sortList } = useDynamicList([ { name: 'my bro', age: '23', memo: "he's my bro" }, { name: 'my sis', age: '21', memo: "she's my sis" }, {}, ]); const [form] = Form.useForm(); const [result, setResult] = useState(''); const columns = [ { title: 'Name', dataIndex: 'name', key: 'name', render: (text: string, row: Item, index: number) => ( <> ), }, { title: 'Age', dataIndex: 'age', key: 'age', render: (text: string, row: Item, index: number) => ( ), }, { key: 'memo', title: 'Memo', dataIndex: 'memo', render: (text: string, row: Item, index: number) => ( <> ), }, ]; return (
move(oldIndex, newIndex)} handleSelector={'span[aria-label="drag"]'} >
getKey(index).toString()} pagination={false} style={{ overflow: 'auto' }} />
{result && `content: ${result}`}
); }; ``` ## API ```typescript const result: Result = useDynamicList(initialValue: T[]); ``` ### Result | Property | Description | Type | Remarks | | --------- | ---------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------ | | list | Current list | `T[]` | - | | resetList | Reset list current data | `(list: T[]) => void` | - | | insert | Add item at specific position | `(index: number, item: T) => void` | - | | merge | Merge items into specific position | `(index: number, items: T[]) => void` | - | | replace | Replace item at specific position | `(index: number, item: T) => void` | - | | remove | Delete specific item | `(index: number) => void` | - | | move | Move item from old index to new index | `(oldIndex: number, newIndex: number) => void` | - | | getKey | Get the uuid of specific item | `(index: number) => number` | - | | getIndex | Retrieve index from uuid | `(key: number) => number` | - | | sortList | Sort the form data(using with antd form) | `(list: T[]) => T[]` | see[`Another way of writing used in antd Form`](#another-way-of-writing-used-in-antd-form) | | push | Push new item at the end of list | `(item: T) => void` | - | | pop | Remove the last item from the list | `() => void` | - | | unshift | Add new item at the front of the list | `(item: T) => void` | - | | shift | Remove the first item from the list | `() => void` | - | ### Params | Property | Description | Type | Default | | ------------ | ------------------------- | ----- | ------- | | initialValue | Initial value of the list | `T[]` | `[]` | # useEventEmitter (/docs/useEventEmitter) ## Overview Sometimes it is difficult to pass events between multiple components. By using EventEmitter, this can be simplified. [Documentation and Examples](https://ahooks.js.org/hooks/use-eventemitter) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useEventEmitter.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useEventEmitter.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useEventEmitter.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useEventEmitter.json ``` Sometimes it is difficult to pass events between multiple components. By using EventEmitter, this can be simplified. To get an instance of `EventEmitter`, you can call `useEventEmitter` in React components. ```js const event$ = useEventEmitter(); ``` > If the component renders multiple times, the return value of `useEventEmitter` in every render process will stay unchanged and no extra `EventEmitter` instance will be created. Then we can share `event$` to other components via `props` or `Context`. To push a event, just call the `emit` method of `EventEmitter`. To subscribe to a series of events, call the `useSubscription` method. ```js event$.emit('hello'); ``` ```js event$.useSubscription(val => { console.log(val); }); ``` > `useSubscription` will automatically register the subscription and unsubscription. If you want to let the child component notify the parent component, you can just use `props` to pass a `onEvent` function. And if you want to let the parent component notify the child component, you can use `forwardRef` to retrieve the ref of child component. `useEventEmitter` is most suitable for event management among multiple components or between two components which are far away. ## Examples ### Parent component shares a event ; }> = function (props) { return (

You received a message

); }; const InputBox: FC<{ focus$: EventEmitter; }> = function (props) { const inputRef = useRef(); props.focus$.useSubscription(() => { inputRef.current.focus(); }); return ( ); }; const Example = () => { const focus$ = useEventEmitter(); return ( <> ); }; export default Example;`} /> ## API ### Params ```typescript const result: Result = useEventEmitter(); ``` ### Result | Property | Description | Type | | --------------- | ----------------------------- | -------------------------------------- | | emit | Emit a new event. | `(val: T) => void` | | useSubscription | Subscribe to a event emitter. | `(callback: (val: T) => void) => void` | # useEventListener (/docs/useEventListener) ## Overview Use addEventListener elegant by Hook. [Documentation and Examples](https://ahooks.js.org/hooks/use-eventlistener) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useEventListener.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useEventListener.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useEventListener.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useEventListener.json ``` Use addEventListener elegant by Hook. ## Examples ### Default usage { const [value, setValue] = useState(0); const ref = useRef(null); useEventListener( 'click', () => { setValue(value + 1); }, { target: ref }, ); return ( ); }; export default Example;`} /> ### Listen for keydown { const [value, setValue] = useState(''); useEventListener('keydown', (ev) => { setValue(ev.code); }); return

Your press key is {value}

; }; export default Example;`} /> ### Listen for multiple events { const ref = useRef(null); const [value, setValue] = useState(''); useEventListener( ['mouseenter', 'mouseleave'], (ev) => { setValue(ev.type); }, { target: ref }, ); return ( ); }; export default Example;`} /> ## API ```typescript useEventListener( eventName: string, handler: (ev: Event) => void, options?: Options, ); ``` ### Property | Property | Description | type | default | | --------- | ---------------------- | ---------------------- | ------- | | eventName | Event name | `string` \| `string[]` | - | | handler | Callback function | `(ev: Event) => void` | - | | options | More options(optional) | `Options` | - | ### Options | Property | Description | type | default | | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | -------- | | target | DOM element or ref | `(() => Element)` \| `Element` \| `React.MutableRefObject` \| `Window` \| `Document` | `window` | | capture | Optional, a Boolean indicating that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree. | `boolean` | `false` | | once | Optional, A Boolean indicating that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked. | `boolean` | `false` | | passive | Optional, A Boolean which, if true, indicates that the function specified by listener will never call preventDefault(). If a passive listener does call preventDefault(), the user agent will do nothing other than generate a console warning. | `boolean` | `false` | | enable | Optional, Whether to enable listening. | `boolean` | `true` | # useEventTarget (/docs/useEventTarget) ## Overview A hook that encapsulates `onChange` and `value` logic for form controls that obtains value through `event.target.value`. It also supports custom transformer and reset functionalities. [Documentation and Examples](https://ahooks.js.org/hooks/use-eventtarget) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useEventTarget.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useEventTarget.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useEventTarget.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useEventTarget.json ``` A hook that encapsulates `onChange` and `value` logic for form controls that obtains value through `event.target.value`. It also supports custom transformer and reset functionalities. ## Example ### Basic Usage { const [value, { reset, onChange }] = useEventTarget({ initialValue: 'this is initial value' }); return (
); }; export default Example;`} /> ### Custom transformer { const [value, { onChange, reset }] = useEventTarget({ initialValue: '', transformer: (val: string) => val.replace(/[^\d]/g, ''), }); return (
); }; export default Example;`} /> ## API ```typescript const [value, { onChange, reset }] = useEventTarget(Options); ``` ### Result | Property | Description | Type | | -------- | ------------------------------------------- | --------------------------------------- | | value | component value | `T` | | onChange | callback when value changes | `(e: { target: { value: T } }) => void` | | reset | function to reset the value to initialValue | `() => void` | ### Options | Property | Description | Type | Default | | ------------ | ------------------------------------------ | ----------------- | ------- | | initialValue | initial value | `T` | - | | transformer | custom transform function applied to value | `(value: U) => T` | - | # useExternal (/docs/useExternal) ## Overview Dynamically load JS or CSS, useExternal can ensure that the resource are globally unique. [Documentation and Examples](https://ahooks.js.org/hooks/use-external) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useExternal.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useExternal.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useExternal.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useExternal.json ``` Dynamically load JS or CSS, useExternal can ensure that the resource are globally unique. ## Example ### Basic Usage { const status = useExternal('https://shadcn-ahooks-docs.vercel.app/useExternal/test-external-script.js', { js: { async: true, }, }); return ( <>

Status: {status}

Response: {status === 'ready' ? window.TEST_SCRIPT?.start() : '-'}

); }; export default Example;`} /> ### Load CSS { const [path, setPath] = useState('https://shadcn-ahooks-docs.vercel.app/useExternal/bootstrap-badge.css'); const status = useExternal(path); return ( <>

Status: {status}

Primary Secondary Success Danger Warning Info Light Dark

); }; export default Example;`} /> ## API ```typescript const status = useExternal(path: string, options?: Options); ``` ### Result | Params | Description | Type | | ------ | -------------------------------------------------------------------------------------------- | -------- | | status | The progress of loading the external resources, support `unset`, `loading`, `ready`, `error` | `string` | ### Params | Params | Description | Type | Default | | ------ | --------------------------------- | -------- | ------- | | path | The url of the external resources | `string` | - | ### Options | Params | Description | Type | Default | | -------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------- | ------- | | type | The type of external resources which need to load, support `js`/`css`, if no type, it will deduced according to path | `string` | - | | js | Attributes supported by `script` | `HTMLScriptElement` | - | | css | Attributes supported by `link` | `HTMLStyleElement` | - | | keepWhenUnused | Allow resources to remain after they have lost their references | `boolean` | `false` | # useFavicon (/docs/useFavicon) ## Overview A hook that set the favicon of the page. [Documentation and Examples](https://ahooks.js.org/hooks/use-favicon) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFavicon.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFavicon.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFavicon.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFavicon.json ``` A hook that set the favicon of the page. ## Example ### Basic Usage { const [url, setUrl] = useState(DEFAULT_FAVICON_URL); useFavicon(url); return ( <>

Current Favicon: {url}

); }; export default Example;`} /> ## API ```typescript useFavicon(href: string); ``` ### Params | Params | Description | Type | Default | | ------ | -------------------------------------------- | -------- | ------- | | href | favicon URL, support `svg`/`png`/`ico`/`gif` | `string` | - | ## FAQ ### It doesn't work in Safari? Safari cannot set the favicon dynamically. > Apple intentionally do not want the ability to script favicons. See [https://bugs.webkit.org/show\_bug.cgi?id=95979#c2](https://bugs.webkit.org/show_bug.cgi?id=95979#c2) Related issues: [#2126](https://github.com/alibaba/hooks/issues/2126) # useFocusWithin (/docs/useFocusWithin) ## Overview Monitor whether the current focus is within a certain area, Same as css attribute [:focus-within](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within). [Documentation and Examples](https://ahooks.js.org/hooks/use-focuswithin) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFocusWithin.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFocusWithin.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFocusWithin.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFocusWithin.json ``` ## Examples ### Default usage { const ref = useRef(null); const isFocusWithin = useFocusWithin(ref, { onFocus: () => { console.info('focus'); }, onBlur: () => { console.info('blur'); }, }); return (

isFocusWithin: {JSON.stringify(isFocusWithin)}

); }; export default Example;`} /> ### Pass in DOM element { const isFocusWithin = useFocusWithin(() => document.getElementById('focus-area')); return (

isFocusWithin: {JSON.stringify(isFocusWithin)}

); }; export default Example;`} /> ## API ```typescript const isFocusWithin = useFocusWithin( target, { onFocus, onBlur, onChange } ); ``` ### Params | Property | Description | Type | Default | | -------- | ------------------ | ----------------------------------------------------------- | ------- | | target | DOM element or ref | `() => Element` \| `Element` \| `MutableRefObject` | - | | options | More config | `Options` | - | ### Options | Property | Description | Type | Default | | -------- | --------------------------------------- | ---------------------------------- | ------- | | onFocus | Callback to be executed on focus | `(e: FocusEvent) => void` | - | | onBlur | Callback to be executed on blur | `(e: FocusEvent) => void` | - | | onChange | Callback to be executed on focus change | `(isFocusWithin: boolean) => void` | - | ### Result | Property | Description | Type | | ------------- | ---------------------------------------- | --------- | | isFocusWithin | Whether the focus is in the current area | `boolean` | # useFullscreen (/docs/useFullscreen) ## Overview manages DOM full screen. [Documentation and Examples](https://ahooks.js.org/hooks/use-fullscreen) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFullscreen.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFullscreen.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFullscreen.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFullscreen.json ``` manages DOM full screen. ## Examples ### Default usage ```tsx import useFullscreen from '@/src/hooks/ahooks/useFullscreen'; import React, { useRef } from 'react'; const Example = () => { const ref = useRef(null); const [isFullscreen, { enterFullscreen, exitFullscreen, toggleFullscreen }] = useFullscreen(ref); return (
{isFullscreen ? 'Fullscreen' : 'Not fullscreen'}
); }; export default Example; ``` ### Image full screen ```tsx import React from 'react'; import { useFullscreen } from 'ahooks'; import img from './react-hooks.jpg'; export default () => { const [, { enterFullscreen }] = useFullscreen(() => document.getElementById('fullscreen-img')); return (
); }; ``` ### Page full screen ```tsx import React, { useRef } from 'react'; import { useFullscreen } from 'ahooks'; export default () => { const ref = useRef(null); const [isFullscreen, { toggleFullscreen, enterFullscreen, exitFullscreen }] = useFullscreen(ref, { pageFullscreen: true, }); return (
{isFullscreen ? 'Fullscreen' : 'Not fullscreen'}
); }; ``` ### Coexist with other full screen operations ```tsx import React, { useRef } from 'react'; import { useFullscreen } from 'ahooks'; function vanillaToggleFullscreen(element) { const isFullscreen = !!document.fullscreenElement; if (isFullscreen) { document.exitFullscreen(); } else { element.requestFullscreen(); } } export default () => { const ref = useRef(null); const [isFullscreen, { toggleFullscreen }] = useFullscreen(ref); return (
{isFullscreen ? 'Fullscreen' : 'Not fullscreen'}
); }; ``` ## API ```typescript const [isFullscreen, { enterFullscreen, exitFullscreen, toggleFullscreen, isEnabled, }] = useFullScreen( target, options?: Options ); ``` ### Params | Property | Description | Type | Default | | -------- | ------------------ | ----------------------------------------------------------- | ------- | | target | DOM element or ref | `Element` \| `() => Element` \| `MutableRefObject` | - | | options | Setting | `Options` | - | ### Options | Property | Description | Type | Default | | -------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ------- | | onExit | Exit full screen trigger | `() => void` | - | | onEnter | Enter full screen trigger | `() => void` | - | | pageFullscreen | Whether to enable full screen of page. If its type is object, it can set `className` and `z-index` of the full screen element | `boolean` \| `{ className?: string, zIndex?: number }` | `false` | ### Result | Property | Description | Type | | ---------------- | -------------------- | ------------ | | isFullscreen | Is full screen | `boolean` | | enterFullscreen | Enter full screen | `() => void` | | exitFullscreen | Exit full screen | `() => void` | | toggleFullscreen | Toggle full screen | `() => void` | | isEnabled | Is enable screenfull | `boolean` | # useFusionTable (/docs/useFusionTable) ## Overview useFusionTable encapsulates the commonly used [Fusion Form](https://fusion.design/pc/component/basic/form) and [Fusion Table](https://fusion.design/pc/component/basic/table) data binding logic. [Documentation and Examples](https://ahooks.js.org/hooks/use-fusiontable) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFusionTable.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFusionTable.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFusionTable.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useFusionTable.json ``` useFusionTable encapsulates the commonly used [Fusion Form](https://fusion.design/pc/component/basic/form) and [Fusion Table](https://fusion.design/pc/component/basic/table) data binding logic. `useFusionTable` is implemented based on `useRequest`. Before using it, you need to understand a few points that are different from `useRequest`: 1. `service` receives two parameters, the first parameter is the paging data `{ current, pageSize, sorter, filters }`, and the second parameter is the form data. 2. The data structure returned by `service` must be `{ total: number, list: Item[] }`. 3. Additional `tableProps`、`paginationProps` and `search` fields will be returned to manage tables and forms. 4. When `refreshDeps` changes, it will reset `current` to the first page and re-initiate the request. ## Examples ### Table management `useFusionTable` will automatically manage the pagination data of `Table`, you only need to pass the returned `tableProps` and `paginationProps` to the corresponding components. ```tsx | pure
```
```tsx import { Pagination, Table } from '@alifd/next'; import React from 'react'; import { useFusionTable } from 'ahooks'; interface Item { name: { last: string; }; email: string; phone: string; gender: 'male' | 'female'; } interface Result { total: number; list: Item[]; } const getTableData = ({ current, pageSize }): Promise => { const query = `page=${current}&size=${pageSize}`; return fetch(`https://randomuser.me/api?results=${pageSize}&${query}`) .then((res) => res.json()) .then((res) => ({ total: 55, list: res.results.slice(0, 10), })); }; const AppList = () => { const { paginationProps, tableProps } = useFusionTable(getTableData); return ( <>
); }; export default AppList; ``` ### Form and Table data binding When `useFusionTable` receives the `field` instance, it will return a search object to handle form related events. * `search.type` supports switching between `simple` and `advance` * `search.changeType`, switch form type * `search.submit` submit form * `search.reset` reset the current form In the following example, you can experience the data binding between form and table. ```tsx import React from 'react'; import { Table, Pagination, Field, Form, Input, Button, Icon } from '@alifd/next'; import { useFusionTable } from 'ahooks'; import ReactJson from 'react-json-view'; interface Item { name: { last: string; }; email: string; phone: string; gender: 'male' | 'female'; } interface Result { total: number; list: Item[]; } const getTableData = ({ current, pageSize }, formData: Object): Promise => { let query = `page=${current}&size=${pageSize}`; Object.entries(formData).forEach(([key, value]) => { if (value) { query += `&${key}=${value}`; } }); return fetch(`https://randomuser.me/api?results=${pageSize}&${query}`) .then((res) => res.json()) .then((res) => ({ total: 55, list: res.results.slice(0, 10), })); }; const AppList = () => { const field = Field.useField([]); const { paginationProps, tableProps, search, loading, params } = useFusionTable(getTableData, { field, }); const { type, changeType, submit, reset } = search; const advanceSearchForm = (
Search
); const searchForm = (
} placeholder="enter name" onPressEnter={submit} />
); return ( <> {type === 'simple' ? searchForm : advanceSearchForm}

Current Table:

Current Form:

); }; export default AppList; ``` ### Default Params `useFusionTable` sets the initial value through `defaultParams`, `defaultParams` is an array, the first item is paging related parameters, and the second item is form related data. If there is a second value, we will initialize the form for you! It should be noted that the initial form data can be filled with all the form data of `simple` and `advance`, and we will help you select the form data of the currently activated type. The following example sets paging data and form data during initialization. ```tsx import { Button, Field, Form, Icon, Input, Pagination, Select, Table } from '@alifd/next'; import React from 'react'; import { useFusionTable } from 'ahooks'; import ReactJson from 'react-json-view'; interface Item { name: { last: string; }; email: string; phone: string; gender: 'male' | 'female'; } interface Result { total: number; list: Item[]; } const getTableData = ({ current, pageSize }, formData: Object): Promise => { let query = `page=${current}&size=${pageSize}`; Object.entries(formData).forEach(([key, value]) => { if (value) { query += `&${key}=${value}`; } }); return fetch(`https://randomuser.me/api?results=${pageSize}&${query}`) .then((res) => res.json()) .then((res) => ({ total: 55, list: res.results.slice(0, 10), })); }; const AppList = () => { const field = Field.useField([]); const { paginationProps, tableProps, search, loading, params } = useFusionTable(getTableData, { field, defaultParams: [ { current: 2, pageSize: 5 }, { name: 'hello', email: 'abc@gmail.com', gender: 'female' }, ], defaultType: 'advance', }); const { type, changeType, submit, reset } = search; const advanceSearchForm = (
Search
); const searchForm = (
} placeholder="enter name" onPressEnter={submit} />
); return ( <> {type === 'simple' ? searchForm : advanceSearchForm}

Current Table:

Current Form:

); }; export default AppList; ``` ### Form Validation Before the form is submitted, we will automatically validate the form data. If the verification fails, the request will not be initiated. ```tsx import React from 'react'; import { Table, Pagination, Field, Form, Input, Select, Icon } from '@alifd/next'; import { useFusionTable } from 'ahooks'; import ReactJson from 'react-json-view'; interface Item { name: { last: string; }; email: string; phone: string; gender: 'male' | 'female'; } interface Result { total: number; list: Item[]; } const getTableData = ({ current, pageSize }, formData: Object): Promise => { let query = `page=${current}&size=${pageSize}`; Object.entries(formData).forEach(([key, value]) => { if (value) { query += `&${key}=${value}`; } }); return fetch(`https://randomuser.me/api?results=${pageSize}&${query}`) .then((res) => res.json()) .then((res) => ({ total: 55, list: res.results.slice(0, 10), })); }; const AppList = () => { const field = Field.useField([]); const { paginationProps, tableProps, search, params } = useFusionTable(getTableData, { field, defaultParams: [{ current: 1, pageSize: 10 }, { name: 'hello' }], }); const { submit } = search; const searchForm = (
} placeholder="enter name" onPressEnter={submit} {...field.init('name', { rules: [{ required: true }] })} />
); return ( <> {searchForm}

Current Table:

Current Form:

); }; export default AppList; ``` ### Data Caching By setting `cacheKey`, we can apply the data caching for the `Form` and `Table` . ```tsx import React, { useState } from 'react'; import { Table, Pagination, Field, Form, Input, Button } from '@alifd/next'; import { useFusionTable } from 'ahooks'; import ReactJson from 'react-json-view'; interface Item { name: { last: string; }; email: string; phone: string; gender: 'male' | 'female'; } interface Result { total: number; list: Item[]; } const getTableData = ( { current, pageSize, filters, sorter }, formData: Object, ): Promise => { console.log(sorter, filters); let query = `page=${current}&size=${pageSize}`; Object.entries(formData).forEach(([key, value]) => { if (value) { query += `&${key}=${value}`; } }); return fetch(`https://randomuser.me/api?results=${pageSize}&${query}`) .then((res) => res.json()) .then((res) => ({ total: 55, list: res.results, })); }; const AppList = () => { const field = Field.useField([]); const { tableProps, paginationProps, params, search } = useFusionTable(getTableData, { defaultPageSize: 5, field, cacheKey: 'tableProps', }); const { filters = {} } = params[0] || {}; const { type, changeType, submit, reset } = search || {}; const searchFrom = (
{type === 'advance' && ( <> )} Search
); return (
{searchFrom}

Current Table:

Current Form:

); }; const Demo = () => { const [show, setShow] = useState(true); return (
{show && }
); }; export default Demo; ``` ## API All parameters and returned results of `useRequest` are applicable to `useFusionTable`, so we won't repeat them here. ```typescript type Data = { total: number; list: any[] }; type Params = [{ current: number; pageSize: number, filter?: any, sorter?: any }, { [key: string]: any }]; const { ..., tableProps: { dataSource: TData['list']; loading: boolean; onSort: (dataIndex: string, order: string) => void; onFilter: (filterParams: any) => void; }; paginationProps: { onChange: (current: number) => void; onPageSizeChange: (size: number) => void; current: number; pageSize: number; total: number; }; search: { type: 'simple' | 'advance'; changeType: () => void; submit: () => void; reset: () => void; }; } = useFusionTable( service: (...args: TParams) => Promise, { ..., field?: any; defaultType?: 'simple' | 'advance'; defaultParams?: TParams, defaultPageSize?: number; refreshDeps?: any[]; } ); ``` ### Result \| Property | Description | Type | \| -- | | | | -- | \| field | `Form` instance | - | - | \| defaultType | Default form type | `simple` | `advance` | `simple` | \| defaultParams | Default parameters, the first item is paging data, the second item is form data | `[pagination, formData]` | - | \| defaultPageSize | Default page size | `number` | `10` | \| refreshDeps | Changes in `refreshDeps` will reset current to the first page and re-initiate the request. | `React.DependencyList` | `[]` | # useGetState (/docs/useGetState) ## Overview Add a getter method to the return value of `React.useState` to get the latest value [Documentation and Examples](https://ahooks.js.org/hooks/use-getstate) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useGetState.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useGetState.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useGetState.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useGetState.json ``` Add a getter method to the return value of `React.useState` to get the latest value ## Examples ### Default usage { const [count, setCount, getCount] = useGetState(0); useEffect(() => { const interval = setInterval(() => { console.log('interval count', getCount()); }, 3000); return () => { clearInterval(interval); }; }, []); return ; }; export default Example;`} /> ## TypeScript definition ```typescript import { Dispatch, SetStateAction } from 'react'; type GetStateAction = () => S; function useGetState(initialState: S | (() => S)): [S, Dispatch>, GetStateAction]; function useGetState(): [S | undefined, Dispatch>, GetStateAction]; ``` ## API ```typescript const [state, setState, getState] = useGetState(initialState) ``` # useHistoryTravel (/docs/useHistoryTravel) ## Overview A hook to manage state change history. It provides encapsulation methods to travel through the history. [Documentation and Examples](https://ahooks.js.org/hooks/use-historytravel) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useHistoryTravel.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useHistoryTravel.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useHistoryTravel.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useHistoryTravel.json ``` A hook to manage state change history. It provides encapsulation methods to travel through the history. ## Examples ### Basic usage { const { value, setValue, backLength, forwardLength, back, forward } = useHistoryTravel(); return (
setValue(e.target.value)} />
); }; export default Example;`} /> ### Todo List { const { value = [], setValue, backLength, forwardLength, back, forward, go, reset, } = useHistoryTravel(['do homework']); const [inputValue, setInputValue] = useState(''); const [step, setStep] = useState(-1); const onAdd = () => { setValue([...value, inputValue]); setInputValue(''); }; const onGo = () => { go(step); setStep(0); }; const onReset = () => { reset(); setStep(0); setInputValue(''); }; return (

TODO List

    {value.map((it, index) => (
  • {it}
  • ))}
setInputValue(e.target.value)} placeholder="Please enter TODO name" style={{ width: 200, marginRight: 8 }} />
setStep(e.target.value as any)} max={forwardLength} min={backLength * -1} style={{ marginRight: 8, width: 60 }} />
); }; export default Example;`} /> ### Limit maximum history length { const maxLength = 3; const { value, setValue, backLength, forwardLength, back, forward } = useHistoryTravel( '', maxLength, ); return (
maxLength: {maxLength}
backLength: {backLength}
forwardLength: {forwardLength}
setValue(e.target.value)} />
); }; export default Example;`} /> ## API ```typescript const { value, setValue, backLength, forwardLength, go, back, forward } = useHistoryTravel(initialValue?: T, maxLength: number = 0 ); ``` ### Params | Property | Description | Type | Default | | ------------ | ------------------------------------------------------------------------------------------------------------------------- | -------- | ----------- | | initialValue | Optional initial value | `T` | - | | maxLength | Optional limit the maximum length of history records. If the maximum length is exceeded, the first record will be deleted | `number` | 0 unlimited | ### Result | Property | Description | Type | | ------------- | --------------------------------------------------------------------------------- | ------------------------------- | | value | Current value | `T` | | setValue | Set value | `(value: T) => void` | | backLength | The length of backward history | `number` | | forwardLength | The length of forward history | `number` | | go | Move between the history, move backward on step \< 0,and move forward on step > 0 | `(step: number) => void` | | back | Move one step backward | `() => void` | | foward | Move one step forward | `() => void` | | reset | Reset history to initial value by default or provide a new initial value. | `(newInitialValue?: T) => void` | # useHover (/docs/useHover) ## Overview A hook that tracks whether the element is being hovered. [Documentation and Examples](https://ahooks.js.org/hooks/use-hover) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useHover.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useHover.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useHover.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useHover.json ``` A hook that tracks whether the element is being hovered. ## Examples ### Default usage { const ref = useRef(null); const isHovering = useHover(ref); return
{isHovering ? 'hover' : 'leaveHover'}
; }; export default Example;`} /> ### Pass in DOM element { const isHovering = useHover(() => document.getElementById('hover-div'), { onEnter: () => { console.log('onEnter'); }, onLeave: () => { console.log('onLeave'); }, onChange: (isHover) => { console.log('onChange', isHover); }, }); return
{isHovering ? 'hover' : 'leaveHover'}
; }; export default Example;`} /> ## API ```javascript const isHovering = useHover( target, { onEnter, onLeave, onChange } ); ``` ### Params | Property | Description | Type | Default | | -------- | ------------------ | ----------------------------------------------------------- | ------- | | target | DOM element or ref | `() => Element` \| `Element` \| `MutableRefObject` | - | | options | More config | `Options` | - | ### Options | Property | Description | Type | Default | | -------- | --------------------------------------- | ------------------------------- | ------- | | onEnter | Callback to be executed on mouse hover | `() => void` | - | | onLeave | Callback to be executed on mouse leave | `() => void` | - | | onChange | Callback to be executed on hover change | `(isHovering: boolean) => void` | - | ### Result | Property | Description | Type | | ---------- | ------------------------------------ | --------- | | isHovering | Whether the element is being hovered | `boolean` | # useInViewport (/docs/useInViewport) ## Overview Observe whether the element is in the visible area, and the visible area ratio of the element. More information refer to [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). [Documentation and Examples](https://ahooks.js.org/hooks/use-inviewport) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInViewport.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInViewport.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInViewport.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInViewport.json ``` Observe whether the element is in the visible area, and the visible area ratio of the element. More information refer to [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). ## Examples ### Default usage { const ref = useRef(null); const [inViewport] = useInViewport(ref); return (
scroll here
observer dom
inViewport: {inViewport ? 'visible' : 'hidden'}
); }; export default Example;`} /> ### Observe the visible area ratio of element * Observe element visible area ratio * Pass in options.threshold, you can control the ratio to be triggered when the visible area reach every threshold. options.root can control the parent element, in this example, visible will not change relative to the browser viewport. { const [inViewport, ratio] = useInViewport(() => document.getElementById('children'), { threshold: [0, 0.25, 0.5, 0.75, 1], root: () => document.getElementById('parent'), }); return (
scroll here
observer dom

inViewport: {inViewport ? 'visible' : 'hidden'}

ratio: {ratio}

); }; export default Example;`} /> ### Listening content scrolling selection menu * Pass the callback that is triggered when the callback of IntersectionObserver is called, so you can do some customization. { const menuRef = useRef([]); const [activeMenu, setActiveMenu] = useState(menus[0]); const callback = useMemoizedFn((entry) => { if (entry.isIntersecting) { const active = entry.target.getAttribute('id') || ''; setActiveMenu(active); } }); const handleMenuClick = (index) => { const contentEl = document.getElementById('content-scroll'); const top = menuRef.current[index]?.offsetTop; contentEl?.scrollTo({ top, behavior: 'smooth', }); }; useInViewport(menuRef.current, { callback, root: () => document.getElementById('parent-scroll'), rootMargin: '-50% 0px -50% 0px', }); return (
    {menus.map((menu, index) => (
  • handleMenuClick(index)} style={{ padding: '10px', cursor: 'pointer', textAlign: 'center', transition: 'background-color 0.2s ease-in-out', backgroundColor: activeMenu === menu ? '#e0e0e0' : '', }} > {menu}
  • ))}
{menus.map((menu, index) => (
{ menuRef.current[index] = el; }} key={menu} id={menu} style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%', fontSize: 16, }} > {content[menu]}
))}
); }; export default Example;`} /> ## API ```typescript type Target = Element | (() => Element) | React.MutableRefObject; const [inViewport, ratio] = useInViewport( target: Target | Target[], options?: Options ); ``` ### Params | Property | Description | Type | Default | | -------- | ---------------------------------- | ------------------------ | ------- | | target | DOM elements or Ref, support array | `Target` \| `Target[]` | - | | options | Setting | `Options` \| `undefined` | - | ### Options More information refer to [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) | Property | Description | Type | Default | | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------- | | threshold | Either a single number or an array of numbers which indicate at what percentage of the target's visibility the ratio should be executed | `number` \| `number[]` | - | | rootMargin | Margin around the root | `string` | - | | root | The element that is used as the viewport for checking visibility of the target. Must be the ancestor of the target. Defaults to the browser viewport if not specified or if null. | `Element` \| `Document` \| `() => (Element/Document)` \| `MutableRefObject` | - | | callback | Triggered when the callback of `IntersectionObserver` is called | `(entry: IntersectionObserverEntry) => void` | - | ### Result | Property | Description | Type | | ---------- | ---------------------------------------------------------------------------------------- | ------------------------ | | inViewport | Is visible | `boolean` \| `undefined` | | ratio | Current visible ratio, updated every time the node set by `options.threshold` is reached | `number` \| `undefined` | # useInfiniteScroll (/docs/useInfiniteScroll) ## Overview useInfiniteScroll encapsulates the common infinite scroll logic. [Documentation and Examples](https://ahooks.js.org/hooks/use-infinitescroll) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInfiniteScroll.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInfiniteScroll.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInfiniteScroll.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInfiniteScroll.json ``` useInfiniteScroll encapsulates the common infinite scroll logic. ```js const { data, loading, loadingMore, loadMore } = useInfiniteScroll(service); ``` The first parameter `service` of useInfiniteScroll is an asynchronous function. The input and output parameters of this function have the following conventions: 1. The data returned by `service` must contain a `list` array, the type is `{ list: any[], ...rest }` 2. The input parameter of `service` is the latest merged `data` If the data returned for the first request is `{ list: [1, 2, 3], nextId: 4 }`, the data returned for the second time is `{ list: [4, 5, 6], nextId: 7 }` , then we will automatically merge `list`, and the merged `data` will be `{ list: [1, 2, 3, 4, 5, 6], nextId: 7 }`. ## Basic usage In the first example, we demonstrate the implementation of a most basic infinite scroll. { let start = 0; if (nextId) { start = resultData.findIndex((i) => i === nextId); } const end = start + limit; const list = resultData.slice(start, end); const nId = resultData.length >= end ? resultData[end] : undefined; return new Promise((resolve) => { setTimeout(() => { resolve({ list, nextId: nId, }); }, 1000); }); } const Example = () => { const { data, loading, loadMore, loadingMore } = useInfiniteScroll((d) => getLoadMoreList(d?.nextId, 4), ); return (
{loading ? (

loading

) : (
{data?.list?.map((item) => (
item-{item}
))}
)}
{data?.nextId && ( )} {!data?.nextId && No more data}
); }; export default Example;`} /> ## Pagination In the data fixation scenario, we sometimes use `page` and `pageSize` to request new data. { const start = (page - 1) * pageSize; const end = page * pageSize; const list = resultData.slice(start, end); return new Promise((resolve) => { setTimeout(() => { resolve({ list, total: resultData.length, }); }, 1000); }); } const PAGE_SIZE = 4; const Example = () => { const { data, loading, loadMore, loadingMore } = useInfiniteScroll((d) => { const page = d ? Math.ceil(d.list.length / PAGE_SIZE) + 1 : 1; return getLoadMoreList(page, PAGE_SIZE); }); const hasMore = data && data.list.length < data.total; return (
{loading ? (

loading

) : (
{data?.list?.map((item) => (
item-{item}
))}
)}
{hasMore && ( )} {!hasMore && No more data}
); }; export default Example;`} /> ## Scrolling to automatically load In the infinite scrolling scenario, the most common case is to automatically load when scrolling to the bottom. By configuring the following properties, you can achieve scrolling to automatically load. * `options.target` specifies the parent element, The parent element needs to set a fixed height and support internal scrolling * `options.isNoMore` determines if there is no more data * `options.direction` determines the direction of scrolling, the default is `bottom` the scroll to bottom demo { let start = 0; if (nextId) { start = resultData.findIndex((i) => i === nextId); } const end = start + limit; const list = resultData.slice(start, end); const nId = resultData.length >= end ? resultData[end] : undefined; return new Promise((resolve) => { setTimeout(() => { resolve({ list, nextId: nId, }); }, 1000); }); } const Example = () => { const ref = useRef(null); const { data, loading, loadMore, loadingMore, noMore } = useInfiniteScroll( (d) => getLoadMoreList(d?.nextId, 4), { target: ref, isNoMore: (d) => d?.nextId === undefined, }, ); return (
{loading ? (

loading

) : (
{data?.list?.map((item) => (
item-{item}
))}
)}
{!noMore && ( )} {noMore && No more data}
); }; export default Example;`} /> the scroll to top demo { let start = 0; if (nextId) { start = resultData.findIndex((i) => i === nextId); } const end = start + limit; const list = resultData.slice(start, end).reverse(); const nId = resultData.length >= end ? resultData[end] : undefined; return new Promise((resolve) => { setTimeout(() => { resolve({ list, nextId: nId, }); }, 1000); }); } const Example = () => { const ref = useRef(null); const isFirstIn = useRef(true); const { data, loading, loadMore, loadingMore, noMore } = useInfiniteScroll( (d) => getLoadMoreList(d?.nextId, 5), { target: ref, direction: 'top', threshold: 0, isNoMore: (d) => d?.nextId === undefined, onSuccess() { if (isFirstIn.current) { isFirstIn.current = false; setTimeout(() => { const el = ref.current; if (el) { el.scrollTo(0, 999999); } }); } }, }, ); return (
{loading ? (

loading

) : (
{!noMore && ( )} {noMore && No more data}
{data?.list?.map((item) => (
item-{item}
))}
)}
); }; export default Example;`} /> ## Data reset The data can be reset by `reload`. The following example shows that after the `filter` changes, the data is reset to the first page. { let start = 0; if (nextId) { start = resultData.findIndex((i) => i === nextId); } const end = start + limit; const list = resultData.slice(start, end); const nId = resultData.length >= end ? resultData[end] : undefined; return new Promise((resolve) => { setTimeout(() => { resolve({ list, nextId: nId, }); }, 1000); }); } const Example = () => { const [keyword, setKeyword] = useState(''); const { data, loading, loadMore, loadingMore, reload } = useInfiniteScroll((d) => getLoadMoreList(d?.nextId, 4, keyword), ); return (
setKeyword(e.target.value)} />
{loading ? (

loading

) : (
{data?.list?.map((item) => (
item-{item}
))}
)}
{data?.nextId && ( )} {!data?.nextId && No more data}
); }; export default Example;`} /> The above code can be implemented with `reloadDeps` syntax sugar. When `reloadDeps` changes, `reload` will be triggered automatically. ```ts const result = useInfiniteScroll(service, { reloadDeps: [keyword] }); ``` ## Data mutation With `mutate`, we can directly modify the current `data`. The following example demonstrates deleting a record from the data. { let start = 0; if (nextId) { start = resultData.findIndex((i) => i === nextId); } const end = start + limit; const list = resultData.slice(start, end); const nId = resultData.length >= end ? resultData[end] : undefined; return new Promise((resolve) => { setTimeout(() => { resolve({ list, nextId: nId, }); }, 1000); }); } function deleteItem(id: string) { return new Promise((resolve) => { setTimeout(() => { resolve(); }, 1000); }); } const Example = () => { const { data, loading, loadMore, loadingMore, mutate } = useInfiniteScroll((d) => getLoadMoreList(d?.nextId, 4), ); const { loading: deleteLading, params: deleteParams, run: remove, } = useRequest(deleteItem, { manual: true, onSuccess: (_, [id]) => { if (data) { const index = data.list.findIndex((i) => i === id); data?.list.splice(index, 1); mutate({ ...data }); } }, }); return (
{loading ? (

loading

) : (
{data?.list?.map((item) => (
item-{item}
))}
)}
{data?.nextId && ( )} {!data?.nextId && No more data}
); }; export default Example;`} /> ## API ```ts export type Data = { list: any[];[key: string]: any; }; export type Service = (currentData?: TData) => Promise; const { data: TData; loading: boolean; loadingMore: boolean; error?: Error; noMore: boolean; loadMore: () => void; loadMoreAsync: () => Promise; reload: () => void; reloadAsync: () => Promise; cancel: () => void; mutate: (data?: TData) => void; } = useInfiniteScroll( service: (currentData?: TData) => Promise, { target?: BasicTarget; isNoMore?: (data?: TData) => boolean; threshold?: number; manual?: boolean; reloadDeps?: DependencyList; onBefore?: () => void; onSuccess?: (data: TData) => void; onError?: (e: Error) => void; onFinally?: (data?: TData, e?: Error) => void; } ); ``` ### Result | Property | Description | Type | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | | data | The data returned by the service, where the `list` attribute is the aggregated data | `TData` \| `undefined` | | loading | Is the first request in progress | `boolean` | | loadingMore | Is more data request in progress | `boolean` | | noMore | Whether there is no more data, it will take effect after configuring `options.isNoMore` | `boolean` | | error | Request error message | `Error` | | loadMore | Load more data, it will automatically catch the exception, and handle it through `options.onError` | `() => void` | | loadMoreAsync | Load more data, which is consistent with the behavior of `loadMore`, but returns Promise, so you need to handle the exception yourself | `() => Promise` | | reload | Load the first page of data, it will automatically catch the exception, and handle it through `options.onError` | `() => void` | | reloadAsync | Load the first page of data, which is consistent with the behavior of `reload`, but returns Promise, so you need to handle the exception yourself | `() => Promise` | | mutate | Modify `data` directly | `(data?: TData) => void` | | cancel | Ignore the current promise response | `() => void` | ### Options | Property | Description | Type | Default | | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | -------- | | target | specifies the parent element. If it exists, it will trigger the `loadMore` when scrolling to the bottom. Needs to work with `isNoMore` to know when there is no more data to load. **when target is document, it is defined as the entire viewport** | `() => Element` \| `Element` \| `MutableRefObject` | - | | isNoMore | determines if there is no more data, the input parameter is the latest merged `data` | `(data?: TData) => boolean` | - | | threshold | The pixel threshold to the bottom for the scrolling to load | `number` | `100` | | direction | The direction of the scrolling | `bottom` \|`top` | `bottom` | | reloadDeps | When the content of the array changes, `reload` will be triggered | `any[]` | - | | manual |
  • The default is `false`. That is, the service is automatically executed during initialization.
  • If set to `true`, you need to manually call `run` or `runAsync` to trigger execution
| `boolean` | `false` | | onBefore | Triggered before service execution | `() => void` | - | | onSuccess | Triggered when service resolve | `(data: TData) => void` | - | | onError | Triggered when service reject | `(e: Error) => void` | - | | onFinally | Triggered when service execution is complete | `(data?: TData, e?: Error) => void` | - | # useInterval (/docs/useInterval) ## Overview A hook that handles the `setInterval` timer function. [Documentation and Examples](https://ahooks.js.org/hooks/use-interval) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInterval.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInterval.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInterval.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInterval.json ``` A hook that handles the `setInterval` timer function. ## Examples ### Default usage { const [count, setCount] = useState(0); useInterval(() => { setCount(count + 1); }, 1000); return
count: {count}
; }; export default Example;`} /> ### Advanced usage { const [count, setCount] = useState(0); const [interval, setInterval] = useState(1000); const clear = useInterval(() => { setCount(count + 1); }, interval); return (

count: {count}

interval: {interval}

); }; export default Example;`} /> ## API ```typescript useInterval( fn: () => void, delay?: number | undefined, options?: Options ): fn: () => void; ``` ### Params | Property | Description | Type | | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | | fn | The function to be executed every `delay` milliseconds. | `() => void` | | delay | The time in milliseconds, the timer should delay in between executions of the specified function. The timer will be cancelled if delay is set to `undefined`. | `number` \| `undefined` | | options | Config of the interval behavior. | `Options` | ### Options | Property | Description | Type | Default | | --------- | ---------------------------------------------------------------------- | --------- | ------- | | immediate | Whether the function should be executed immediately on first execution | `boolean` | `false` | ### Result | Property | Description | Type | | ------------- | -------------- | ------------ | | clearInterval | clear interval | `() => void` | # useIsomorphicLayoutEffect (/docs/useIsomorphicLayoutEffect) ## Overview In SSR mode, the following warning will appear when useLayoutEffect is used [Documentation and Examples](https://ahooks.js.org/hooks/use-isomorphiclayouteffect) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useIsomorphicLayoutEffect.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useIsomorphicLayoutEffect.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useIsomorphicLayoutEffect.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useIsomorphicLayoutEffect.json ``` In SSR mode, the following warning will appear when useLayoutEffect is used > ⚠️ Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See [https://fb.me/react-uselayouteffect-ssr](https://fb.me/react-uselayouteffect-ssr) for common fixes. To avoid this warning, useIsomorphicLayoutEffect can be used instead of useLayoutEffect. The source code of useIsomorphicLayoutEffect is: ```javascript const useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect; ``` Return useLayoutEffect for browser environment and useEffect for other environments. For more information, please refer to [useLayoutEffect and SSR](https://medium.com/@alexandereardon/uselayouteffect-and-ssr-192986cdcf7a) # useKeyPress (/docs/useKeyPress) ## Overview Listen for the keyboard press, support key combinations, and support alias. [Documentation and Examples](https://ahooks.js.org/hooks/use-keypress) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useKeyPress.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useKeyPress.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useKeyPress.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useKeyPress.json ``` Listen for the keyboard press, support key combinations, and support alias. ## Examples ### Basic usage { const [counter, setCounter] = useState(0); useKeyPress('uparrow', () => { setCounter((s) => s + 1); }); // keyCode value for ArrowDown useKeyPress(40, () => { setCounter((s) => s - 1); }); return (

Try pressing the following:

1. Press ArrowUp by key to increase
2. Press ArrowDown by keyCode to decrease
counter: {counter}
); }; export default Example;`} /> ### Combination keys { const [state, setState] = useState(); useKeyPress(['shift.c'], () => { setState(1); }); useKeyPress(['meta'], () => { setState(2); }); useKeyPress('ctrl.alt.c', () => { setState(3); }); useKeyPress('ctrl.enter', () => { setState(4); }); // Attention: event.key === '0' useKeyPress('ctrl.alt.0', () => { setState(5); }); return (

Try pressing the following:

1. Modifier key [shift.c]: {state === 1 && }
2. Modifier key [meta]: {state === 2 && }
3. Modifier key [ctrl.alt.c]: {state === 3 && }
4. Modifier key [ctrl.enter]: {state === 4 && }
5. Modifier key [ctrl.alt.0]: {state === 5 && }
); }; export default Example;`} /> ### Exact match { const [state, setState] = useState(); useKeyPress(['shift.c'], () => { setState(1); }); useKeyPress( ['c'], () => { setState(2); }, { exactMatch: true, }, ); return (

Try pressing the following:

1. Modifier key [shift.c]: {state === 1 && }
2. Modifier key [c]: {state === 2 && }
); }; export default Example;`} /> ### Multiple keys { const [num, setNum] = useState(); const [key, setKey] = useState(); const filterKey = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; useKeyPress(filterKey, (event) => { setNum(event.key); }); // a s d f, Backspace, 8 useKeyPress([65, 83, 68, 70, 8, '8'], (event) => { setKey(event.key); }); return (

Try pressing the following:

1. Number key [0-9]: {num}
2. Press key [a, s, d, f, Backspace, 8]: {key}
); }; export default Example;`} /> ### Get the trigger key { const [count, setCount] = useState(0); const keyCallbackMap = { w: () => { setCount((prev) => prev + 1); }, s: () => { setCount((prev) => prev - 1); }, 'shift.c': () => { setCount(0); }, }; useKeyPress(['w', 's', 'shift.c'], (e, key) => { keyCallbackMap[key](); }); return (

Try pressing the following:

1. Press [w] to increase
2. Press [s] to decrease
3. Press [shift.c] to reset

counter: {count}

); }; export default Example;`} /> ### Custom method { const [key, setKey] = useState(); const filterKey = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; useKeyPress( (event) => !filterKey.includes(event.key), (event) => { if (event.type === 'keyup') { setKey(event.key); } }, { events: ['keydown', 'keyup'], }, ); return (
Pressing key except number key:{key}
); }; export default Example;`} /> ### Custom DOM { const inputRef = useRef(null); const [text, setText] = useState(''); const [textRef, setTextRef] = useState(''); const [textSync, setTextSync] = useState(''); useKeyPress( 'enter', (event: any) => { const { value } = event.target; setText(value); }, { events: ['keyup'], target: () => document.getElementById('input'), }, ); useKeyPress( 'enter', (event: any) => { const { value } = event.target; setTextRef(value); }, { target: inputRef, }, ); // Make sure the DOM exists useKeyPress( () => true, (event: any) => { const { value } = event.target; setTextSync(value); }, { events: ['keyup'], target: document.getElementById('input2'), }, ); return (

Input and pressing enter: {text}

Input and pressing enter: {textRef}

Input after enter change: {textSync}

); }; export default Example;`} /> ## API ```typescript type KeyType = number | string; type KeyFilter = KeyType | KeyType[] | ((event: KeyboardEvent) => boolean); useKeyPress( keyFilter: KeyFilter, eventHandler: (event: KeyboardEvent, key: KeyType) => void, options?: Options ); ``` ### Params | Property | Description | Type | Default | | ------------ | ------------------------------------------------------------ | --------------------------------------------------------------- | ------- | | keyFilter | Support keyCode、alias、combination keys、array、custom function | `KeyType` \| `KeyType[]` \| `(event: KeyboardEvent) => boolean` | - | | eventHandler | Callback function | `(event: KeyboardEvent, key: KeyType) => void` | - | | options | Advanced options | `Options` | - | ### Options | Property | Description | Type | Default | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- | ------------- | | events | Trigger Events | `('keydown' \| 'keyup')[]` | `['keydown']` | | target | DOM element or ref | `() => Element` \| `Element` \| `MutableRefObject` | - | | exactMatch | Exact match. If set `true`, the event will only be trigger when the keys match exactly. For example, pressing \[shift + c] will not trigger \[c] | `boolean` | `false` | | useCapture | to block events bubbling | `boolean` | `false` | ## Remarks 1. All key alias refer to [code](https://github.com/alibaba/hooks/blob/master/packages/hooks/src/useKeyPress/index.ts#L21) 2. Modifier keys ```text ctrl alt shift meta ``` # useLatest (/docs/useLatest) ## Overview A Hook that returns the latest value, effectively avoiding the closure problem. [Documentation and Examples](https://ahooks.js.org/hooks/use-latest) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLatest.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLatest.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLatest.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLatest.json ``` A Hook that returns the latest value, effectively avoiding the closure problem. ## Examples ### Basic usage { const [count, setCount] = useState(0); const [count2, setCount2] = useState(0); const latestCountRef = useLatest(count); useEffect(() => { const interval = setInterval(() => { setCount(latestCountRef.current + 1); }, 1000); return () => clearInterval(interval); }, []); useEffect(() => { const interval = setInterval(() => { setCount2(count2 + 1); }, 1000); return () => clearInterval(interval); }, []); return ( <>

count(useLatest): {count}

count(default): {count2}

); }; export default Example;`} /> ## API ```typescript const latestValueRef = useLatest(value: T): MutableRefObject; ``` # useLocalStorageState (/docs/useLocalStorageState) ## Overview A Hook that store state into localStorage. [Documentation and Examples](https://ahooks.js.org/hooks/use-localstoragestate) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLocalStorageState.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLocalStorageState.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLocalStorageState.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLocalStorageState.json ``` A Hook that store state into localStorage. ## Examples ### Store state into localStorage { const [message, setMessage] = useLocalStorageState( 'use-local-storage-state-demo1', { defaultValue: 'Hello~', }, ); return ( <> setMessage(e.target.value)} /> ); }; export default Example;`} /> ### Store complex types of data { const [value, setValue] = useLocalStorageState('use-local-storage-state-demo2', { defaultValue: defaultArray, }); return ( <>

{value?.join('-')}

); }; export default Example;`} /> ### Custom serialization and deserialization functions { const [message, setMessage] = useLocalStorageState( 'use-local-storage-state-demo3', { defaultValue: 'Hello~', serializer: (v) => v ?? '', deserializer: (v) => v, }, ); return ( <> setMessage(e.target.value)} /> ); }; export default Example;`} /> ### Sync state with localStorage ); } const Example = () => { return ( <> ); }; export default Example;`} /> ## API If you want to delete this record from localStorage, you can use `setState()` or `setState(undefined)`. ```typescript type SetState = S | ((prevState?: S) => S); interface Options { defaultValue?: T | (() => T); listenStorageChange?: boolean; serializer?: (value: T) => string; deserializer?: (value: string) => T; onError?: (error: unknown) => void; } const [state, setState] = useLocalStorageState( key: string, options: Options ): [T?, (value?: SetState) => void]; ``` ### Result | Property | Description | Type | | -------- | --------------------------- | ------------------------------- | | state | Local `localStorage` value | `T` | | setState | Update `localStorage` value | `(value?: SetState) => void` | ### Options | Property | Description | Type | Default | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | ----------------------------- | | defaultValue | Default value | `any \| (() => any)` | - | | listenStorageChange | Whether to listen storage changes. If `true`, when the stored value changes, all `useLocalStorageState` with the same `key` will synchronize their states, including different tabs of the same browser | `boolean` | `false` | | serializer | Custom serialization method | `(value: any) => string` | `JSON.stringify` | | deserializer | Custom deserialization method | `(value: string) => any` | `JSON.parse` | | onError | On error callback | `(error: unknown) => void` | `(e) => { console.error(e) }` | ## Remark useLocalStorageState will call `serializer` before write data to localStorage, and call `deserializer` once after read data. # useLockFn (/docs/useLockFn) ## Overview Add lock to an async function to prevent parallel executions. [Documentation and Examples](https://ahooks.js.org/hooks/use-lockfn) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLockFn.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLockFn.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLockFn.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLockFn.json ``` Add lock to an async function to prevent parallel executions. ## Examples ### Basic usage ((resolve) => { setTimeout(() => { resolve(); }, 2000); }); } const Example = () => { const [count, setCount] = useState(0); const submit = useLockFn(async () => { console.log('Start to submit'); await mockApiRequest(); setCount((val) => val + 1); console.log('Submit finished'); }); return ( <>

Submit count: {count}

); }; export default Example;`} /> ## API ```typescript function useLockFn

( fn: (...args: P) => Promise ): fn: (...args: P) => Promise; ``` ### Result | Property | Description | Type | | -------- | ---------------------------- | ---------------------------------- | | fn | The async function with lock | `(...args: any[]) => Promise` | ### Params | Property | Description | Type | Default | | -------- | ----------------- | ---------------------------------- | ------- | | fn | An async function | `(...args: any[]) => Promise` | - | # useLongPress (/docs/useLongPress) ## Overview Listen for the long press event of the target element. [Documentation and Examples](https://ahooks.js.org/hooks/use-longpress) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLongPress.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLongPress.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLongPress.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useLongPress.json ``` Listen for the long press event of the target element. ## Examples ### Basic usage ((resolve) => { setTimeout(() => { resolve(); }, 2000); }); } const Example = () => { const [counter, setCounter] = useState(0); const ref = useRef(null); useLongPress(() => setCounter((s) => s + 1), ref); return (

counter: {counter}

); }; export default Example;`} /> ### Listen for click and long press events at the same time ((resolve) => { setTimeout(() => { resolve(); }, 2000); }); } const Example = () => { const [pressCounter, setPressCounter] = useState(0); const [clickCounter, setClickCounter] = useState(0); const ref = useRef(null); useLongPress(() => setPressCounter((s) => s + 1), ref, { onClick: () => setClickCounter((s) => s + 1), }); return (

pressCounter: {pressCounter}

clickCounter: {clickCounter}

); }; export default Example;`} /> ### Move threshold ((resolve) => { setTimeout(() => { resolve(); }, 2000); }); } const Example = () => { const [pressCounter, setPressCounter] = useState(0); const ref = useRef(null); useLongPress(() => setPressCounter((s) => s + 1), ref, { moveThreshold: { x: 30 }, }); return (

counter: {pressCounter}

); }; export default Example;`} /> ## API ```typescript useLongPress( onLongPress: (event: MouseEvent | TouchEvent) => void, target: Target, options: { delay?: number; moveThreshold?: { x?: number; y?: number }; onClick?: (event: MouseEvent | TouchEvent) => void; onLongPressEnd?: (event: MouseEvent | TouchEvent) => void; } ); ``` ### Params | Property | Description | Type | Default | | ----------- | ---------------------------- | ----------------------------------------------------------- | ------- | | onLongPress | Trigger function | `(event: MouseEvent \| TouchEvent) => void` | - | | target | DOM node or Ref | `Element` \| `() => Element` \| `MutableRefObject` | - | | options | Optional configuration items | `Options` | `{}` | ### Options | Property | Description | Type | Default | | -------------- | ----------------------------------------------------------------------------------- | ------------------------------------------- | ------- | | delay | Long press time | `number` | `300` | | moveThreshold | Move threshold after press. If exceeded, the long press function won't be triggered | `{ x?: number; y?: number }` | - | | onClick | Click event | `(event: MouseEvent \| TouchEvent) => void` | - | | onLongPressEnd | Long press end event | `(event: MouseEvent \| TouchEvent) => void` | - | ### Remark Please refer to: [https://stackoverflow.com/a/11237968](https://stackoverflow.com/a/11237968) to disable the ability to long press to select text on the phone # useMap (/docs/useMap) ## Overview A hook that can manage the state of Map. [Documentation and Examples](https://ahooks.js.org/hooks/use-map) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMap.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMap.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMap.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMap.json ``` A hook that can manage the state of Map. ## Examples ### Default usage ((resolve) => { setTimeout(() => { resolve(); }, 2000); }); } const Example = () => { const [map, { set, setAll, remove, reset, get }] = useMap([ ['msg', 'hello world'], [123, 'number type'], ]); return (
{JSON.stringify(Array.from(map), null, 2)}
); }; export default Example;`} /> ## API ```typescript const [ map, { set, setAll, remove, reset, get } ] = useMap(initialValue); ``` ### Result | Property | Description | Type | | -------- | ---------------- | ------------------------------------ | | map | Map object | `Map` | | set | Add item | `(key: K, value: V) => void` | | get | Get item | `(key: K) => V \| undefined` | | setAll | Set a new Map | `(newMap: Iterable<[K, V]>) => void` | | remove | Remove key | `(key: K) => void` | | reset | Reset to default | `() => void` | ### Params | Property | Description | Type | Default | | ------------ | --------------------------- | ------------------ | ------- | | initialValue | Optional, set default value | `Iterable<[K, V]>` | - | # useMemoizedFn (/docs/useMemoizedFn) ## Overview Hooks for persistent functions. In general, useMemoizedFn can be used instead of useCallback. See [FAQ](#faq) for special cases. [Documentation and Examples](https://ahooks.js.org/hooks/use-memoizedfn) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMemoizedFn.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMemoizedFn.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMemoizedFn.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMemoizedFn.json ``` Hooks for persistent functions. In general, useMemoizedFn can be used instead of useCallback. See [FAQ](#faq) for special cases. In some scenarios, we need to use useCallback to cache a function, but when the second parameter deps changes, the function will be regenerated, causing the function reference to change. ```js const [state, setState] = useState(''); // When the state changes, the func reference will change const func = useCallback(() => { console.log(state); }, [state]); ``` Using useMemoizedFn, you can omit the second parameter deps, and ensure that the function reference never change. ```js const [state, setState] = useState(''); // func reference never change const func = useMemoizedFn(() => { console.log(state); }); ``` ## Examples ### Default usage { const [count, setCount] = useState(0); const callbackFn = useCallback(() => { console.info(\`Current count is \${count}\`); }, [count]); const memoizedFn = useMemoizedFn(() => { console.info(\`Current count is \${count}\`); }); return ( <>

count: {count}

); }; export default Example;`} /> ### Performance Improvement (({ showCount }) => { const renderCountRef = useRef(0); renderCountRef.current += 1; return (

Render Count: {renderCountRef.current}

); }); const Example = () => { const [count, setCount] = useState(0); const callbackFn = useCallback(() => { console.info(\`Current count is \${count}\`); }, [count]); const memoizedFn = useMemoizedFn(() => { console.info(\`Current count is \${count}\`); }); return ( <>

count: {count}

You can click the button to see the number of sub-component renderings

Component with useCallback function:

{/* use callback function, ExpensiveTree component will re-render on state change */}

Component with useMemoizedFn function:

{/* use memoized function, ExpensiveTree component will only render once */}
); }; export default Example;`} /> ## API ```typescript const memoizedFn = useMemoizedFn(fn: T): T; ``` ### Result | Property | Description | Type | | ---------- | ------------------------------------------------- | ------------------------- | | memoizedFn | Function that the reference address never changes | `(...args: any[]) => any` | ### Params | Property | Description | Type | Default | | -------- | --------------------------------- | ------------------------- | ------- | | fn | Function that require persistence | `(...args: any[]) => any` | - | ## FAQ ### The function returned by `useMemoizedFn` will not inherit properties from fn itself? The function returned by `useMemoizedFn` is entirely different from the reference of the passed `fn`, and it does not inherit any properties from `fn` itself. If you want to preserve the properties of the function itself after memoization, `useMemoizedFn` currently does not fulfill that requirement. In this case, consider downgrading to using `useCallback` or `useMemo` instead. Related issues: [2273](https://github.com/alibaba/hooks/issues/2273) # useMount (/docs/useMount) ## Overview A hook that executes a function after the component is mounted. [Documentation and Examples](https://ahooks.js.org/hooks/use-mount) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMount.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMount.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMount.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMount.json ``` A hook that executes a function after the component is mounted. ## Examples ### Default Usage { useMount(() => { console.info('mount'); return () => { console.info('unmount'); }; }); return
Hello World
; }; const Example = () => { const [state, { toggle }] = useBoolean(false); return ( <> {state && } ); }; export default Example;`} /> ## API ```typescript useMount(fn: EffectCallback); ``` ### Params | Property | Description | Type | Default | | -------- | --------------------------- | ---------------- | ------- | | fn | The function to be executed | `EffectCallback` | - | # useMouse (/docs/useMouse) ## Overview Track cursor position [Documentation and Examples](https://ahooks.js.org/hooks/use-mouse) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMouse.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMouse.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMouse.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMouse.json ``` Track cursor position ## Examples ### Default Usage { const mouse = useMouse(); return (

Client - x: {mouse.clientX}, y: {mouse.clientY}

Page - x: {mouse.pageX}, y: {mouse.pageY}

Screen - x: {mouse.screenX}, y: {mouse.screenY}

); }; export default Example;`} /> ### Mouse position relative to the element { const ref = useRef(null); const mouse = useMouse(ref.current); return ( <>
element

Mouse In Element - x: {mouse.elementX}, y: {mouse.elementY}

Element Position - x: {mouse.elementPosX}, y: {mouse.elementPosY}

Element Dimensions - width: {mouse.elementW}, height: {mouse.elementH}

); }; export default Example;`} /> ## API ```typescript const state: { screenX: number, screenY: number, clientX: number, clientY: number, pageX: number, pageY: number, elementX: number, elementY: number, elementH: number, elementW: number, elementPosX: number, elementPosY: number, } = useMouse(target?: Target); ``` ### Params | Property | Description | Type | Default | | -------- | ------------------ | ----------------------------------------------------------- | ------- | | target | DOM element or ref | `() => Element` \| `Element` \| `MutableRefObject` | - | ### result | Property | Description | Type | | ----------- | ------------------------------------------------------------------------------------------------------------------ | -------- | | screenX | Position left relative to the top left of the physical screen/monitor | `number` | | screenY | Position top relative to the top left of the physical screen/monitor | `number` | | clientX | Position left relative to the upper left edge of the content area | `number` | | clientY | Position top relative to the upper left edge of the content area | `number` | | pageX | Position left relative to the top left of the fully rendered content area in the browser | `number` | | pageY | Position top relative to the top left of the fully rendered content area in the browser | `number` | | elementX | Position left relative to the upper left edge of the target element | `number` | | elementY | Position top relative to the upper left edge of the target element | `number` | | elementH | Target element height | `number` | | elementW | Target element width | `number` | | elementPosX | The position of the target element left relative to the top left of the fully rendered content area in the browser | `number` | | elementPosY | The position of the target element top relative to the top left of the fully rendered content area in the browser | `number` | # useMutationObserver (/docs/useMutationObserver) ## Overview A hook that provides the ability to watch for changes being made to the DOM tree, refer to [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) [Documentation and Examples](https://ahooks.js.org/hooks/use-mutationobserver) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMutationObserver.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMutationObserver.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMutationObserver.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useMutationObserver.json ``` A hook that provides the ability to watch for changes being made to the DOM tree, refer to [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) ## Examples ### Default Usage { const [width, setWidth] = useState(200); const [count, setCount] = useState(0); const ref = useRef(null); useMutationObserver( (mutationsList) => { mutationsList.forEach(() => setCount((c) => c + 1)); }, ref, { attributes: true }, ); return (
current width:{width}

Mutation count {count}

); }; export default Example;`} /> ## API ```typescript useMutationObserver( callback: MutationCallback, target: Target, options?: MutationObserverInit, ); ``` ## Params | Property | Description | Type | Default | | -------- | --------------------- | ------------------------------------------------------------------- | ------- | | target | DOM element or ref | `() => Element` \| `Element` \| `MutableRefObject` | - | | callback | The callback function | `(mutations: MutationRecord[], observer: MutationObserver) => void` | - | | options | Setting | `MutationObserverInit` | - | ### Options For options, please refer to [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe#parameters) # useNetwork (/docs/useNetwork) ## Overview A hook that tracks the state of network connection. [Documentation and Examples](https://ahooks.js.org/hooks/use-network) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useNetwork.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useNetwork.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useNetwork.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useNetwork.json ``` A hook that tracks the state of network connection. ## Examples ### Default usage { const networkState = useNetwork(); return (
Network information:
{JSON.stringify(networkState, null, 2)}
); }; export default Example;`} /> ## API ```typescript interface NetworkState { online?: boolean; since?: Date; rtt?: number; type?: string; downlink?: number; saveData?: boolean; downlinkMax?: number; effectiveType?: string; } const result: NetworkState = useNetwork(); ``` ### Result | Property | Description | Type | | ------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | | online | Whether connected to network | `boolean` | | since | `online` latest update time | `Date` | | rtt | The effective round-trip time estimate in milliseconds | `number` | | type | The connection type that the user agent is using | `bluetooth` \| `cellular` \| `ethernet` \| `none` \| `wifi` \| `wimax` \| `other` \| `unknown` | | downlink | The effective bandwidth estimate in megabits per second, | `number` | | downlinkMax | An upper bound on the downlink speed of the first network hop | `number` | | saveData | Whether the user agent has set the option to reduce data usage | `boolean` | | effectiveType | The effective connection type | `slow-2g` \| `2g` \| `3g` \| `4g` | More information refer to [MDN NetworkInformation](https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation) # usePagination (/docs/usePagination) ## Overview `usePagination` is implemented based on `useRequest` and encapsulates common paging logic. The differences from `useRequest` are as follows: [Documentation and Examples](https://ahooks.js.org/hooks/use-pagination) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/usePagination.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/usePagination.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/usePagination.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/usePagination.json ``` `usePagination` is implemented based on `useRequest` and encapsulates common paging logic. The differences from `useRequest` are as follows: 1. The first parameter of `service` is `{ current: number, pageSize: number }` 2. The data structure returned by `service` is `{ total: number, list: Item[] }` 3. It will additionally return the `pagination` field, which contains all the pagination information and functions to operate the pagination. 4. When `refreshDeps` changes, it will reset `current` to the first page and re-initiate the request. Generally, you can put the conditions that `pagination` depends on here ## Examples ### Basic usage The default usage is the same as `useRequest`, but an additional `pagination` parameter will be returned, which contains all pagination information and functions to operate pagination. ```tsx import { usePagination } from 'ahooks'; import { Pagination } from 'antd'; import Mock from 'mockjs'; import React from 'react'; interface UserListItem { id: string; name: string; gender: 'male' | 'female'; email: string; disabled: boolean; } const userList = (current: number, pageSize: number) => Mock.mock({ total: 55, [`list|${pageSize}`]: [ { id: '@guid', name: '@name', 'gender|1': ['male', 'female'], email: '@email', disabled: false, }, ], }); async function getUserList(params: { current: number; pageSize: number; }): Promise<{ total: number; list: UserListItem[] }> { return new Promise((resolve) => { setTimeout(() => { resolve(userList(params.current, params.pageSize)); }, 1000); }); } const Example = () => { const { data, loading, pagination } = usePagination(getUserList); return (
{loading ? (

loading

) : (
    {data?.list?.map((item) => (
  • {item.name} - {item.email}
  • ))}
)}
); }; export default Example; ``` ### More parameters The following code demonstrates that the gender parameter is added. When the gender is modified, the paging is reset to the first page and the data is requested again. ```tsx import { Pagination } from 'antd'; import Mock from 'mockjs'; import React, { useEffect, useState } from 'react'; import { usePagination } from 'ahooks'; interface UserListItem { id: string; name: string; gender: 'male' | 'female'; email: string; disabled: boolean; } const userList = (current: number, pageSize: number) => Mock.mock({ total: 55, [`list|${pageSize}`]: [ { id: '@guid', name: '@name', 'gender|1': ['male', 'female'], email: '@email', disabled: false, }, ], }); async function getUserList(params: { current: number; pageSize: number; gender: string; }): Promise<{ total: number; list: UserListItem[] }> { return new Promise((resolve) => { setTimeout(() => { resolve(userList(params.current, params.pageSize)); }, 1000); }); } export default () => { const [gender, setGender] = useState('male'); const { data, loading, pagination, run, params } = usePagination( ({ current, pageSize }, g: string) => { return getUserList({ current, pageSize, gender: g, }); }, { manual: true, }, ); useEffect(() => { run( { current: 1, pageSize: params[0]?.pageSize || 10, }, gender, ); }, [gender]); return (
{loading ? (

loading

) : (
    {data?.list?.map((item) => (
  • {item.name} - {item.email}
  • ))}
)}
); }; ``` ### refreshDeps `refreshDeps` is a syntactic sugar. When it changes, it will reset the page to the first page and request data again. Generally, you can put the dependent conditions here. The following example implements the previous function more conveniently through `refreshDeps`. ```tsx import { usePagination } from 'ahooks'; import { useUpdateEffect } from 'ahooks'; import { Pagination } from 'antd'; import Mock from 'mockjs'; import React, { useState } from 'react'; interface UserListItem { id: string; name: string; gender: 'male' | 'female'; email: string; disabled: boolean; } const userList = (current: number, pageSize: number) => Mock.mock({ total: 55, [`list|${pageSize}`]: [ { id: '@guid', name: '@name', 'gender|1': ['male', 'female'], email: '@email', disabled: false, }, ], }); async function getUserList(params: { current: number; pageSize: number; gender: string; }): Promise<{ total: number; list: UserListItem[] }> { return new Promise((resolve) => { setTimeout(() => { resolve(userList(params.current, params.pageSize)); }, 1000); }); } export default () => { const [gender, setGender] = useState('male'); const { data, loading, pagination } = usePagination( ({ current, pageSize }) => { return getUserList({ current, pageSize, gender, }); }, { refreshDeps: [gender], }, ); return (
{loading ? (

loading

) : (
    {data?.list?.map((item) => (
  • {item.name} - {item.email}
  • ))}
)}
); }; ``` ### Cache Through the `params` caching capability of `useRequest`, we can cache paging data and other conditions. ```tsx import { useBoolean, useUpdateEffect } from 'ahooks'; import { Pagination } from 'antd'; import Mock from 'mockjs'; import React, { useState } from 'react'; import { usePagination } from 'ahooks'; interface UserListItem { id: string; name: string; gender: 'male' | 'female'; email: string; disabled: boolean; } const userList = (current: number, pageSize: number) => Mock.mock({ total: 55, [`list|${pageSize}`]: [ { id: '@guid', name: '@name', 'gender|1': ['male', 'female'], email: '@email', disabled: false, }, ], }); async function getUserList(params: { current: number; pageSize: number; gender: string; }): Promise<{ total: number; list: UserListItem[] }> { console.log('cache demo', params.current, params.pageSize, params.gender); return new Promise((resolve) => { setTimeout(() => { resolve(userList(params.current, params.pageSize)); }, 1000); }); } const PaginationComponent: React.FC = () => { const { data, loading, pagination, run, params } = usePagination( ({ current, pageSize }, g: string) => { return getUserList({ current, pageSize, gender: g, }); }, { cacheKey: 'userList', }, ); const [gender, setGender] = useState(params[1] || 'male'); useUpdateEffect(() => { run( { current: 1, pageSize: params[0]?.pageSize || 10, }, gender, ); }, [gender]); return (
{loading && !data ? (

loading

) : (
    {data?.list?.map((item) => (
  • {item.name} - {item.email}
  • ))}
)}
); }; export default () => { const [state, { toggle }] = useBoolean(); return (

You can click the button multiple times, the conditions of pagination will be cached.

{state && }
); }; ``` ## API All parameters and returned results of `useRequest` are applicable to `usePagination`, so we won't repeat them here. ```typescript type Data = { total: number; list: T[] }; type Params = [{ current: number; pageSize: number, [key: string]: any }, ...any[]]; const { ..., pagination: { current: number; pageSize: number; total: number; totalPage: number; onChange: (current: number, pageSize: number) => void; changeCurrent: (current: number) => void; changePageSize: (pageSize: number) => void; } } = usePagination( service: (...args: TParams) => Promise, { ..., defaultPageSize?: number; refreshDeps?: any[]; } ); ``` ### Result | Property | Description | Type | | ---------- | ------------------------------------------- | ---- | | pagination | Paging data and methods of paging operation | `-` | ### Params | Property | Description | Type | Default | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | ------- | | defaultPageSize | Default page size | `number` | 10 | | defaultCurrent | Number of pages on initial request | `number` | 1 | | refreshDeps | Changes in `refreshDeps` will reset current to the first page and re-initiate the request. Generally, you can put the dependent conditions here. | `React.DependencyList` | `[]` | # usePrevious (/docs/usePrevious) ## Overview A Hook to return the previous state. [Documentation and Examples](https://ahooks.js.org/hooks/use-previous) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/usePrevious.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/usePrevious.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/usePrevious.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/usePrevious.json ``` A Hook to return the previous state. ## Examples ### Default usage { const [count, setCount] = useState(0); const previous = usePrevious(count); return ( <>
counter current value: {count}
counter previous value: {previous}
); }; export default Example;`} /> ### Custom shouldUpdate function { if (!prev) { return true; } if (prev.name !== next.name) { return true; } return false; }; const jobCompareFunction = (prev: Person | undefined, next: Person) => { if (!prev) { return true; } if (prev.job !== next.job) { return true; } return false; }; const Example = () => { const [state, setState] = useState({ name: 'Jack', job: 'student' }); const [nameInput, setNameInput] = useState(''); const [jobInput, setJobInput] = useState(''); const previousName = usePrevious(state, nameCompareFunction); const previousJob = usePrevious(state, jobCompareFunction); return ( <>
current name: {state.name}
current job: {state.job}
previous name: {(previousName || {}).name}
previous job: {(previousJob || {}).job}
setNameInput(e.target.value)} placeholder="new name" />
setJobInput(e.target.value)} placeholder="new job" />
); }; export default Example;`} /> ## API ```typescript const previousState: T = usePrevious( state: T, shouldUpdate?: (prev: T | undefined, next: T) => boolean ); ``` ### Result | Property | Description | Type | | ------------- | ------------------ | ---- | | previousState | The previous value | `T` | ### Params | Property | Description | Type | Default | | ------------ | ------------------------------------------------------------- | -------------------------------------------- | ---------------------------- | | state | The state that needs to be tracked | `T` | - | | shouldUpdate | Optional. Customize whether the state value should be updated | `(prev: T \| undefined, next: T) => boolean` | `(a, b) => !Object.is(a, b)` | # useRafInterval (/docs/useRafInterval) ## Overview A hook implements with `requestAnimationFrame` for better performance. The API is consistent with `useInterval`, the advantage is that the execution of the timer can be stopped when the page is not rendering, such as page hiding or minimization. [Documentation and Examples](https://ahooks.js.org/hooks/use-rafinterval) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRafInterval.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRafInterval.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRafInterval.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRafInterval.json ``` A hook implements with `requestAnimationFrame` for better performance. The API is consistent with `useInterval`, the advantage is that the execution of the timer can be stopped when the page is not rendering, such as page hiding or minimization. Please note that the following two cases are likely to be inapplicable, and `useInterval` is preferred: * the time interval is less than `16ms` * want to execute the timer when page is not rendering; > `requestAnimationFrame` will automatically downgrade to `setInterval` in node environment ## Examples ### Default usage { const [count, setCount] = useState(0); useRafInterval(() => { setCount(count + 1); }, 1000); return
count: {count}
; }; export default Example;`} /> ### Advanced usage { const [count, setCount] = useState(0); const [interval, setInterval] = useState(1000); const clear = useRafInterval(() => { setCount(count + 1); }, interval); return (

count: {count}

interval: {interval}

); }; export default Example;`} /> ## API ```typescript useRafInterval( fn: () => void, delay?: number | undefined, options?: Options ): fn: () => void; ``` ### Params | Property | Description | Type | | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | | fn | The function to be executed every `delay` milliseconds. | `() => void` | | delay | The time in milliseconds, the timer should delay in between executions of the specified function. The timer will be cancelled if delay is set to `undefined`. | `number` \| `undefined` | | options | Config of the interval behavior. | `Options` | ### Options | Property | Description | Type | Default | | --------- | ---------------------------------------------------------------------- | --------- | ------- | | immediate | Whether the function should be executed immediately on first execution | `boolean` | `false` | ### Result | Property | Description | Type | | ------------- | -------------- | ------------ | | clearInterval | clear interval | `() => void` | # useRafState (/docs/useRafState) ## Overview Update the state in [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) callback, generally used for performance optimization. [Documentation and Examples](https://ahooks.js.org/hooks/use-rafstate) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRafState.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRafState.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRafState.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRafState.json ``` Update the state in [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) callback, generally used for performance optimization. ## Examples ### Default usage { const [state, setState] = useRafState({ width: 0, height: 0, }); useEffect(() => { const onResize = () => { setState({ width: document.documentElement.clientWidth, height: document.documentElement.clientHeight, }); }; onResize(); window.addEventListener('resize', onResize); return () => { window.removeEventListener('resize', onResize); }; }, []); return (

Try to resize the window

current: {JSON.stringify(state)}
); }; export default Example;`} /> ### API Same as `React.useState`. # useRafTimeout (/docs/useRafTimeout) ## Overview A hook implements with `requestAnimationFrame` for better performance. The API is consistent with `useTimeout`. the advantage is that will not trigger function when the page is not rendering, such as page hiding or minimization. [Documentation and Examples](https://ahooks.js.org/hooks/use-raftimeout) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRafTimeout.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRafTimeout.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRafTimeout.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRafTimeout.json ``` A hook implements with `requestAnimationFrame` for better performance. The API is consistent with `useTimeout`. the advantage is that will not trigger function when the page is not rendering, such as page hiding or minimization. > `requestAnimationFrame` will automatically downgrade to `setTimeout` in node environment ## Examples ### Default usage { const [count, setCount] = useState(0); useRafTimeout(() => { setCount(count + 1); }, 2000); return
count: {count}
; }; export default Example;`} /> ### Advanced usage { const [count, setCount] = useState(0); const [delay, setDelay] = useState(1000); const clear = useRafTimeout(() => { setCount(count + 1); }, delay); return (

count: {count}

Delay: {delay}

); }; export default Example;`} /> ## API ```typescript useRafTimeout( fn: () => void, delay?: number | undefined, ): fn: () => void; ``` ### Params | Property | Description | Type | | -------- | ---------------------------------------------------------------------------------------------------------------------- | ----------------------- | | fn | The function to be executed after `delay` milliseconds. | `() => void` | | delay | The number of milliseconds to wait before executing the function. The timer will be cancelled if delay is `undefined`. | `number` \| `undefined` | ### Result | Property | Description | Type | | ------------ | ------------- | ------------ | | clearTimeout | clear timeout | `() => void` | # useReactive (/docs/useReactive) ## Overview A React hook from ahooks library [Documentation and Examples](https://ahooks.js.org/hooks/use-reactive) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useReactive.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useReactive.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useReactive.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useReactive.json ``` It offers data reactivity when manipulating states and views, in which case `useState` is unnecessary for state definition. Modifying properties will automatically lead to view rerendering. ## Examples ### Default Usage { const state = useReactive({ count: 0, inputVal: '', obj: { value: '', }, }); return (

state.count:{state.count}

state.inputVal: {state.inputVal}

(state.inputVal = e.target.value)} />

state.obj.value: {state.obj.value}

(state.obj.value = e.target.value)} />
); }; export default Example;`} /> ### Array { const state = useReactive<{ arr: number[] }>({ arr: [], }); return (

state.arr: {JSON.stringify(state.arr)}

); }; export default Example;`} /> ### Computed Properties { const state = useReactive({ bug: '', bugs: ['feat', 'fix', 'chore'], addBug(bug) { this.bugs.push(bug); }, get bugsCount() { return this.bugs.length; }, }); return (

state.bugsCount: {state.bugsCount}

{ state.addBug(state.bug); state.bug = ''; e.preventDefault(); }} > (state.bug = e.target.value)} />

    {state.bugs.map((bug) => (
  • {bug}
  • ))}
); }; export default Example;`} /> ### Notice { const state = useReactive({ count: 0 }); const [stateCount, setStateCount] = useState(0); const state2 = useReactive({ count: 0 }); const [stateCount2, setStateCount2] = useState(0); // Depends on the object, because it is always the same reference, it will not be executed useEffect(() => { setStateCount(stateCount + 1); }, [state]); // Depends on the underlying data type, so as long as it changes, it will be re-executed useEffect(() => { setStateCount2(stateCount2 + 1); }, [state2.count]); return (

stateCount:{stateCount}

stateCount2:{stateCount2}

); }; export default Example;`} /> ## API ```js const state = useReactive(initialValue: Record); ``` ## Params | Params | Description | Type | Default | | ------------ | ------------- | --------------------- | ------- | | initialState | Current state | `Record` | - | ## FAQ ### When `useReactive` is used with `Map`, `Set`, it will throw an error or not work? `useReactive` is not compatible with `Map`, `Set`。 Related issues: [#2239](https://github.com/alibaba/hooks/discussions/2239) # useResetState (/docs/useResetState) ## Overview useResetState works similar to `React.useState`, it provides a `reset` method [Documentation and Examples](https://ahooks.js.org/hooks/use-resetstate) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useResetState.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useResetState.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useResetState.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useResetState.json ``` useResetState works similar to `React.useState`, it provides a `reset` method ## Examples ### Default Usage { const initialValue = { hello: '', value: Math.random(), }; const initialValueMemo = useMemo(() => { return initialValue; }, []); const [state, setState, resetState] = useResetState(initialValue); return (
initial state:
{JSON.stringify(initialValueMemo, null, 2)}
current state:
{JSON.stringify(state, null, 2)}
); }; export default Example;`} /> ## API ```typescript const [state, setState, resetState] = useResetState( initialState: S | (() => S), ): [S, Dispatch>, () => void] ``` # useResponsive (/docs/useResponsive) ## Overview React Hook for getting responsive info. [Documentation and Examples](https://ahooks.js.org/hooks/use-responsive) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useResponsive.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useResponsive.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useResponsive.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useResponsive.json ``` React Hook for getting responsive info. ## Examples ### Get responsive info in components { const responsive = useResponsive(); return ( <>

Please change the width of the browser window to see the effect:

{Object.keys(responsive).map((key) => (

{key} {responsive[key] ? '✔' : '✘'}

))} ); }; export default Example;`} /> ## API ```typescript interface ResponsiveConfig { [key: string]: number; } interface ResponsiveInfo { [key: string]: boolean; } function configResponsive(config: ResponsiveConfig): void; function useResponsive(): ResponsiveInfo; ``` ### Config The default config is the same as bootstrap: ```javascript { 'xs': 0, 'sm': 576, 'md': 768, 'lg': 992, 'xl': 1200, } ``` If you want to config your own responsive breakpoints, you can use `configResponsive`: (Caution: You only need to config it once. Don't call this config function repeatedly.) ```javascript configResponsive({ small: 0, middle: 800, large: 1200, }); ``` # useSafeState (/docs/useSafeState) ## Overview It is exactly the same with `React.useState` , but after the component is unmounted, the `setState` in the asynchronous callback will no longer be executed to avoid memory leakage caused by updating the state after the component is unmounted. [Documentation and Examples](https://ahooks.js.org/hooks/use-safestate) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSafeState.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSafeState.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSafeState.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSafeState.json ``` It is exactly the same with `React.useState` , but after the component is unmounted, the `setState` in the asynchronous callback will no longer be executed to avoid memory leakage caused by updating the state after the component is unmounted. ## Examples ### Basic usage { const [value, setValue] = useSafeState(); useEffect(() => { setTimeout(() => { setValue('data loaded from server'); }, 5000); }, []); const text = value || 'Loading...'; return
{text}
; }; const Example = () => { const [visible, setVisible] = useState(true); return (
{visible && }
); }; export default Example;`} /> ## API ```typescript const [state, setState] = useSafeState(initialState); ``` # useScroll (/docs/useScroll) ## Overview Get the scroll position of an element. [Documentation and Examples](https://ahooks.js.org/hooks/use-scroll) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useScroll.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useScroll.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useScroll.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useScroll.json ``` Get the scroll position of an element. ## Examples ### Basic Usage { const ref = useRef(null); const scroll = useScroll(ref); return ( <>

{JSON.stringify(scroll)}

Lorem ipsum dolor sit amet, consectetur adipisicing elit. A aspernatur atque, debitis ex excepturi explicabo iste iure labore molestiae neque optio perspiciatis
Aspernatur cupiditate, deleniti id incidunt mollitia omnis! A aspernatur assumenda consequuntur culpa cumque dignissimos enim eos, et fugit natus nemo nesciunt
Alias aut deserunt expedita, inventore maiores minima officia porro rem. Accusamus ducimus magni modi mollitia nihil nisi provident
Alias aut autem consequuntur doloremque esse facilis id molestiae neque officia placeat, quia quisquam repellendus reprehenderit.
Adipisci blanditiis facere nam perspiciatis sit soluta ullam! Architecto aut blanditiis, consectetur corporis cum deserunt distinctio dolore eius est exercitationem
Ab aliquid asperiores assumenda corporis cumque dolorum expedita
Culpa cumque eveniet natus totam! Adipisci, animi at commodi delectus distinctio dolore earum, eum expedita facilis
Quod sit, temporibus! Amet animi fugit officiis perspiciatis, quis unde. Cumque dignissimos distinctio, dolor eaque est fugit nisi non pariatur porro possimus, quas quasi
); }; export default Example;`} /> ### Detect Whole Page Scroll { const scroll = useScroll(document); return (
{JSON.stringify(scroll)}
); }; export default Example;`} /> ### Control listen on scroll status { const ref = useRef(null); const scroll = useScroll(ref, (val) => val.top > 100 && val.top < 200); return ( <>

{JSON.stringify(scroll)}

Lorem ipsum dolor sit amet, consectetur adipisicing elit. A aspernatur atque, debitis ex excepturi explicabo iste iure labore molestiae neque optio perspiciatis
Aspernatur cupiditate, deleniti id incidunt mollitia omnis! A aspernatur assumenda consequuntur culpa cumque dignissimos enim eos, et fugit natus nemo nesciunt
Alias aut deserunt expedita, inventore maiores minima officia porro rem. Accusamus ducimus magni modi mollitia nihil nisi provident
Alias aut autem consequuntur doloremque esse facilis id molestiae neque officia placeat, quia quisquam repellendus reprehenderit.
Adipisci blanditiis facere nam perspiciatis sit soluta ullam! Architecto aut blanditiis, consectetur corporis cum deserunt distinctio dolore eius est exercitationem
Ab aliquid asperiores assumenda corporis cumque dolorum expedita
Culpa cumque eveniet natus totam! Adipisci, animi at commodi delectus distinctio dolore earum, eum expedita facilis
Quod sit, temporibus! Amet animi fugit officiis perspiciatis, quis unde. Cumque dignissimos distinctio, dolor eaque est fugit nisi non pariatur porro possimus, quas quasi
); }; export default Example;`} /> ## API ```typescript const position = useScroll(target, shouldUpdate); ``` ### Params | Property | Description | Type | Default | | ------------ | ------------------------- | --------------------------------------------------------------------------- | ------------ | | target | DOM element or ref object | `Element` \| `Document` \| `(() => Element)` \| `MutableRefObject` | `document` | | shouldUpdate | Whether update position | `({ top: number, left: number }) => boolean` | `() => true` | ### Result | Property | Description | Type | | -------- | ------------------------------------------- | -------------------------------------------- | | position | The current scroll position of the element. | `{ left: number, top: number } \| undefined` | # useSelections (/docs/useSelections) ## Overview This hook is used for Checkbox group, supports multiple selection, single selection, select-all, select-none and semi-selected etc. [Documentation and Examples](https://ahooks.js.org/hooks/use-selections) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSelections.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSelections.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSelections.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSelections.json ``` This hook is used for Checkbox group, supports multiple selection, single selection, select-all, select-none and semi-selected etc. ## Examples ### Default usage ```tsx import { Checkbox, Col, Row } from 'antd'; import React, { useMemo, useState } from 'react'; import { useSelections } from 'ahooks'; export default () => { const [hideOdd, setHideOdd] = useState(false); const list = useMemo(() => { if (hideOdd) { return [2, 4, 6, 8]; } return [1, 2, 3, 4, 5, 6, 7, 8]; }, [hideOdd]); const { selected, allSelected, isSelected, toggle, toggleAll, partiallySelected } = useSelections( list, { defaultSelected: [1], }, ); return (
Selected: {selected.join(',')}
Check all setHideOdd((v) => !v)}> Hide Odd
{list.map((o) => ( toggle(o)}> {o} ))}
); }; ``` ### Object array ```tsx import { Checkbox, Col, Row } from 'antd'; import React, { useMemo, useState } from 'react'; import { useSelections } from 'ahooks'; export default () => { const [hideOdd, setHideOdd] = useState(false); const list = useMemo(() => { if (hideOdd) { return [2, 4, 6, 8].map((id) => ({ id })); } return [1, 2, 3, 4, 5, 6, 7, 8].map((id) => ({ id })); }, [hideOdd]); const { selected, allSelected, isSelected, toggle, toggleAll, partiallySelected } = useSelections( list, { defaultSelected: [{ id: 1 }], itemKey: 'id', }, ); return (
Selected: {JSON.stringify(selected)}
Check all setHideOdd((v) => !v)}> Hide Odd
{list.map((item) => ( toggle(item)}> {item.id} ))}
); }; ``` ### Pagination ```tsx import { Checkbox, Divider, Pagination, Spin } from 'antd'; import React, { useEffect, useState } from 'react'; import { useSelections } from 'ahooks'; interface DataType { id: number; title: string; } interface PaginationType { current: number; pageSize: number; total?: number; } const dataSource = Array.from({ length: 50 }, (item, index) => ({ id: index, title: `title ${index}`, })); const getDataFromServer = (props: PaginationType) => { const { current, pageSize } = props; const data = dataSource.slice((current - 1) * pageSize, current * pageSize); return new Promise<{ data: DataType[]; total: PaginationType['total']; }>((resolve) => { setTimeout( () => resolve({ data, total: dataSource.length, }), 500, ); }); }; export default () => { const [dataList, setDataList] = useState([]); const [loading, setLoading] = useState(false); const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0, }); const getData = async (params: PaginationType) => { setLoading(true); const { data, total } = await getDataFromServer(params); setLoading(false); setDataList(data); setPagination({ ...params, total }); }; useEffect(() => { getData(pagination); }, []); const { selected, allSelected, isSelected, toggle, toggleAll, partiallySelected } = useSelections( dataList, { itemKey: 'id', }, ); return ( {dataList.map((item) => { const { id, title } = item; return (
toggle(item)} checked={isSelected(item)} > {title}
); })} { getData({ current: page, pageSize: size, }); }} />
Check all Selected: {selected.length}
{!!selected.length && ( <> {JSON.stringify(selected)} )}
); }; ``` ## API ```typescript interface Options { defaultSelected?: T[]; itemKey?: string | ((item: T) => Key); } // works when >=3.8.0, recommended ✅ const result: Result = useSelections(items: T[], options?: Options); // works when <4.0.0, will be removed in ahooks 4.0 🙅🏻‍♀️ const result: Result = useSelections(items: T[], defaultSelected?: T[]); ``` ### Params | Property | Description | Type | Default | | -------- | ---------------------- | --------- | ------- | | items | Data items | `T[]` | - | | options | Optional configuration | `Options` | - | ### Options | Property | Description | Type | Default | | --------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | ------- | | defaultSelected | Default selected data | `T[]` | `[]` | | itemKey | The unique key of data item. Typically, this parameter needs to be specified when the data source is an array of object | `string` \| `(item: T) => React.Key` | - | ### Result | Property | Description | Type | | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | | selected | Selected items | `T[]` | | allSelected | Is all items selected | `boolean` | | noneSelected | Is no item selected | `boolean` | | partiallySelected | Is partially items selected | `boolean` | | isSelected | Whether item is selected | `(value: T) => boolean` | | setSelected | Select multiple items. When executed multiple times, the later return value overwrites the previous one, so if you want to merge the results of multiple operations, you need to do this manually: `setSelected((oldArray) => oldArray.concat(newArray))` | `(value: T[]) => void \| (value: (prevState: T[]) => T[]) => void` | | select | Select single item | `(value: T) => void` | | unSelect | UnSelect single item | `(value: T) => void` | | toggle | Toggle single item select status | `(value: T) => void` | | selectAll | Select all items | `() => void` | | unSelectAll | UnSelect all items | `() => void` | | toggleAll | Toggle select all items | `() => void` | | clearAll | Clear all selected (In general, `clearAll` is equivalent to `unSelectAll`. If the items is dynamic, `clearAll` will clear "all selected data", while `unSelectAll` will only clear "the currently selected data in the items") | `() => void` | # useSessionStorageState (/docs/useSessionStorageState) ## Overview A Hook for store state into sessionStorage. [Documentation and Examples](https://ahooks.js.org/hooks/use-sessionstoragestate) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSessionStorageState.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSessionStorageState.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSessionStorageState.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSessionStorageState.json ``` A Hook for store state into sessionStorage. Usage is exactly the same as [useLocalStorageState](./useLocalStorageState). # useSet (/docs/useSet) ## Overview A hook that can manage the state of Set. [Documentation and Examples](https://ahooks.js.org/hooks/use-set) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSet.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSet.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSet.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSet.json ``` A hook that can manage the state of Set. ## Examples ### Default usage { const [set, { add, remove, reset }] = useSet(['Hello']); return (
{JSON.stringify(Array.from(set), null, 2)}
); }; export default Example;`} /> ## API ```typescript const [ set, { add, remove, reset } ] = useSet(initialValue); ``` ### Result | Property | Description | Type | | -------- | ---------------- | ------------------ | | set | Set object | `Set` | | add | Add item | `(key: K) => void` | | remove | Remove item | `(key: K) => void` | | reset | Reset to default | `() => void` | ### Params | Property | Description | Type | Default | | ------------ | --------------------------- | ------------- | ------- | | initialValue | Optional, set default value | `Iterable` | - | # useSetState (/docs/useSetState) ## Overview useSetState works similar to `this.setState` of class component, used to manage the state of object type. [Documentation and Examples](https://ahooks.js.org/hooks/use-setstate) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSetState.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSetState.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSetState.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSetState.json ``` useSetState works similar to `this.setState` of class component, used to manage the state of object type. ## Examples ### Default usage { const [state, setState] = useSetState({ hello: '', }); return (
{JSON.stringify(state, null, 2)}

); }; export default Example;`} /> ### Updating with callback { const [state, setState] = useSetState({ hello: 'world', count: 0, }); return (
{JSON.stringify(state, null, 2)}

); }; export default Example;`} /> ## API ```typescript const [state, setState] = useSetState(initialState); ``` ### Result | Property | Description | Type | Default | | -------- | -------------------- | ----------------------------------------------------------------------------------------- | ------- | | state | Current state | `T` | - | | setState | Update current state | `(state: Partial \| null) => void` \| `((prevState: T) => Partial \| null) => void` | - | ### Params | Property | Description | Type | Default | | ------------ | ------------- | -------------- | ------- | | initialState | Initial state | `T \| () => T` | - | # useSize (/docs/useSize) ## Overview A hook that observes size change of an element. [Documentation and Examples](https://ahooks.js.org/hooks/use-size) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSize.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSize.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSize.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useSize.json ``` A hook that observes size change of an element. ## Examples ### Default usage { const ref = useRef(null); const size = useSize(ref); return (

Try to resize the preview window

width: {size?.width}px, height: {size?.height}px

); }; export default Example;`} /> ### Pass in the DOM element { const size = useSize(document.querySelector('body')); return (

Try to resize the preview window

width: {size?.width}px, height: {size?.height}px

); }; export default Example;`} /> ## API ```typescript const size = useSize(target); ``` ### Params | Property | Description | Type | Default | | -------- | ------------------------- | ------------------------------------------------------------- | ------- | | target | DOM element or ref object | `Element` \| `(() => Element)` \| `MutableRefObject` | - | ### Result | Property | Description | Type | Default | | -------- | ------------------- | ------------------------------------------------ | ------------------------------------------------------------------------- | | size | Size of the element | `{ width: number, height: number } \| undefined` | `{ width: target.clientWidth, height: target.clientHeight } \| undefined` | # useTextSelection (/docs/useTextSelection) ## Overview Tracking content, size, position of user text selection. [Documentation and Examples](https://ahooks.js.org/hooks/use-textselection) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTextSelection.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTextSelection.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTextSelection.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTextSelection.json ``` Tracking content, size, position of user text selection. ## Examples ### Default usage { const { text } = useTextSelection(); return (

You can select text all page.

Result:{text}

); }; export default Example;`} /> ### Listen for specified area { const ref = useRef(null); const selection = useTextSelection(ref); return (

Please swipe your mouse to select any text on this paragraph.

Result:{JSON.stringify(selection)}

); }; export default Example;`} /> ### Translate user text selection ```tsx import { useRequest, useTextSelection } from 'ahooks'; import { Popover, Spin } from 'antd'; import React, { useEffect, useState } from 'react'; const getResult = (keyword: string): Promise => { const trimedText = keyword.trim() !== ''; if (!trimedText) { return Promise.resolve(''); } return new Promise((resolve) => { setTimeout(() => resolve(`[translate result] ${keyword}`), 2000); }); }; export default () => { const { text = '', left = 0, top = 0, height = 0, width = 0, } = useTextSelection(() => document.querySelector('#translate-dom')); const [open, setOpen] = useState(false); const { data, run, loading } = useRequest(getResult, { manual: true, }); useEffect(() => { if (text.trim() === '') { setOpen(false); return; } setOpen(true); run(text); }, [text]); return (

Translation of this paragraph;Translation of this paragraph;Translation of this paragraph;

{loading ? 'Translating……' : data}} open={open} >
); }; ``` ## API ```typescript const state = useTextSelection(target?); ``` ### Params | Property | Description | Type | Default | | -------- | ------------------ | ------------------------------------------------------------------------------------ | ---------- | | target | DOM element or ref | `Element` \| `Document` \| `(() => Element\Document)` \| `MutableRefObject` | `document` | ### Result | Property | Description | Type | | -------- | ---------------------------------------------- | ------- | | state | Content, size, position of user text selection | `State` | ### State | Property | Description | Type | | -------- | ----------------------------------- | -------- | | text | Selected text | `string` | | left | The left coordinate value of text | `number` | | right | The right coordinate value of text | `number` | | top | The top coordinate value of text | `number` | | bottom | The bottom coordinate value of text | `number` | | height | The height of text | `number` | | width | The width of text | `number` | # useTheme (/docs/useTheme) ## Overview This hook is used to get and set the theme, and store the `themeMode` into `localStorage`. [Documentation and Examples](https://ahooks.js.org/hooks/use-theme) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTheme.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTheme.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTheme.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTheme.json ``` This hook is used to get and set the theme, and store the `themeMode` into `localStorage`. ## Examples ### Default usage { const { theme, themeMode, setThemeMode } = useTheme({ localStorageKey: 'themeMode', }); return ( <>
theme: {theme}
themeMode: {themeMode}
); }; export default Example;`} /> ## API ```typescript const { theme, themeMode, setThemeMode } = useTheme({ localStorageKey?: string; }); ``` ### Params | Property | Description | Type | Default | | --------------- | ---------------------------------------------------- | -------- | ----------- | | localStorageKey | The key in localStorage to store selected theme mode | `string` | `undefined` | ### Result | Property | Description | Type | Default | | ------------ | --------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------ | | theme | current display theme | `"light" \| "dark"` | if themeMode is "system" then equals to system setting,otherwise equals to themeMode | | themeMode | selected theme mode | `"light" \| "dark" \| "system"` | equals to localStorage "themeMode", otherwise equals to "system" | | setThemeMode | select theme mode | `(mode: "light" \| "dark" \| "system") => void` | | # useThrottle (/docs/useThrottle) ## Overview A hook that deal with the throttled value. [Documentation and Examples](https://ahooks.js.org/hooks/use-throttle) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useThrottle.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useThrottle.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useThrottle.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useThrottle.json ``` A hook that deal with the throttled value. ## Examples ### Default usage { const [value, setValue] = useState(); const throttledValue = useThrottle(value, { wait: 500 }); return (
setValue(e.target.value)} placeholder="Typed value" style={{ width: 280 }} />

throttledValue: {throttledValue}

); }; export default Example;`} /> ## API ```typescript const throttledValue = useThrottle( value: any, options?: Options ); ``` ### Params | Property | Description | Type | Default | | -------- | ---------------------------------- | --------- | ------- | | value | The value to throttle. | `any` | - | | options | Config for the throttle behaviors. | `Options` | - | ### Options | Property | Description | Type | Default | | -------- | ----------------------------------------------------- | --------- | ------- | | wait | The number of milliseconds to delay. | `number` | `1000` | | leading | Specify invoking on the leading edge of the timeout. | `boolean` | `true` | | trailing | Specify invoking on the trailing edge of the timeout. | `boolean` | `true` | # useThrottleEffect (/docs/useThrottleEffect) ## Overview Throttle your `useEffect`. [Documentation and Examples](https://ahooks.js.org/hooks/use-throttleeffect) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useThrottleEffect.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useThrottleEffect.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useThrottleEffect.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useThrottleEffect.json ``` Throttle your `useEffect`. ## Examples ### Default usage { const [value, setValue] = useState('hello'); const [records, setRecords] = useState([]); useThrottleEffect( () => { setRecords((val) => [...val, value]); }, [value], { wait: 1000, }, ); return (
setValue(e.target.value)} placeholder="Typed value" style={{ width: 280 }} />

    {records.map((record, index) => (
  • {record}
  • ))}

); }; export default Example;`} /> ## API ```typescript useThrottleEffect( effect: EffectCallback, deps?: DependencyList, options?: Options ); ``` ### Params | Property | Description | Type | Default | | -------- | ------------------------------------------------------------ | ---------------- | ------- | | effect | The effect callback. | `EffectCallback` | - | | deps | The dependencies list. | `DependencyList` | - | | options | Config the throttle behavior. See the Options section below. | `Options` | - | ### Options | Property | Description | Type | Default | | -------- | ----------------------------------------------------- | --------- | ------- | | wait | The number of milliseconds to wait. | `number` | `1000` | | leading | Specify invoking on the leading edge of the timeout. | `boolean` | `true` | | trailing | Specify invoking on the trailing edge of the timeout. | `boolean` | `true` | # useThrottleFn (/docs/useThrottleFn) ## Overview A hook that deal with the throttled function. [Documentation and Examples](https://ahooks.js.org/hooks/use-throttlefn) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useThrottleFn.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useThrottleFn.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useThrottleFn.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useThrottleFn.json ``` A hook that deal with the throttled function. ## Examples ### Default usage { const [value, setValue] = useState(0); const { run } = useThrottleFn( () => { setValue(value + 1); }, { wait: 500 }, ); return (

Clicked count: {value}

); }; export default Example;`} /> ## API ```typescript const { run, cancel, flush } = useThrottleFn( fn: (...args: any[]) => any, options?: Options ); ``` ### Params | Property | Description | Type | Default | | -------- | --------------------------------- | ------------------------- | ------- | | fn | The function to throttle. | `(...args: any[]) => any` | - | | options | Config for the throttle behaviors | `Options` | - | ### Options | Property | Description | Type | Default | | -------- | ----------------------------------------------------- | --------- | ------- | | wait | The number of milliseconds to delay. | `number` | `1000` | | leading | Specify invoking on the leading edge of the timeout. | `boolean` | `true` | | trailing | Specify invoking on the trailing edge of the timeout. | `boolean` | `true` | ### Result | Property | Description | Type | | -------- | ------------------------------------------------------ | ------------------------- | | run | Invoke and pass parameters to fn. | `(...args: any[]) => any` | | cancel | Cancel the invocation of currently throttled function. | `() => void` | | flush | Immediately invoke currently throttled function | `() => void` | # useTimeout (/docs/useTimeout) ## Overview A hook that handles the `setTimeout` timer function. [Documentation and Examples](https://ahooks.js.org/hooks/use-timeout) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTimeout.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTimeout.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTimeout.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTimeout.json ``` A hook that handles the `setTimeout` timer function. ## Examples ### Default usage { const [state, setState] = useState(1); useTimeout(() => { setState(state + 1); }, 3000); return
{state}
; }; export default Example;`} /> * Modify the delay to realize the timer timeout change and pause. { const [count, setCount] = useState(0); const [delay, setDelay] = useState(1000); const clear = useTimeout(() => { setCount(count + 1); }, delay); return (

count: {count}

Delay: {delay}

); }; export default Example;`} /> ## API ```typescript useTimeout( fn: () => void, delay?: number | undefined ): fn: () => void; ``` ### Params | Property | Description | Type | | -------- | ---------------------------------------------------------------------------------------------------------------------- | ----------------------- | | fn | The function to be executed after `delay` milliseconds. | `() => void` | | delay | The number of milliseconds to wait before executing the function. The timer will be cancelled if delay is `undefined`. | `number` \| `undefined` | ### Result | Property | Description | Type | | ------------ | ------------- | ------------ | | clearTimeout | clear timeout | `() => void` | # useTitle (/docs/useTitle) ## Overview A hook that set title of the page. [Documentation and Examples](https://ahooks.js.org/hooks/use-title) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTitle.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTitle.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTitle.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTitle.json ``` A hook that set title of the page. ## Examples ### Default usage { useTitle('Page Title'); return (

Set title of the page.

); }; export default Example;`} /> ## API ```typescript useTitle(title: string, options?: Options); ``` ### Params | Property | Description | Type | Default | | -------- | ----------- | -------- | ------- | | title | Page title | `string` | - | ### Options | Property | Description | Type | Default | | ---------------- | -------------------------------------------------------------------------- | --------- | ------- | | restoreOnUnmount | Whether to restore the previous page title when the component is unmounted | `boolean` | `false` | # useToggle (/docs/useToggle) ## Overview A hook that toggle states. [Documentation and Examples](https://ahooks.js.org/hooks/use-toggle) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useToggle.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useToggle.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useToggle.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useToggle.json ``` A hook that toggle states. ## Examples ### Default usage { const [state, { toggle, setLeft, setRight }] = useToggle(); return (

Effects:{\`\${state}\`}

); }; export default Example;`} /> ### Advanced usage { const [state, { toggle, set, setLeft, setRight }] = useToggle('Hello', 'World'); return (

Effects:{state}

); }; export default Example;`} /> ## API ```typescript const [state, { toggle, set, setLeft, setRight }] = useToggle(defaultValue?: boolean); const [state, { toggle, set, setLeft, setRight }] = useToggle(defaultValue: T); const [state, { toggle, set, setLeft, setRight }] = useToggle(defaultValue: T, reverseValue: U) ``` ### Params | Property | Description | Type | Default | | ------------ | --------------------------- | ---- | ------- | | defaultValue | The default value. Optional | `T` | `false` | | reverseValue | The reverse value. Optional | `U` | - | ### Result | Property | Description | Type | | -------- | -------------------------------------- | --------- | | state | Current state | - | | actions | A set of methods to update state value | `Actions` | ### Actions | Property | Description | Type | | -------- | ------------------------------------------------------------------------------------------------------------- | ------------------------- | | toggle | Toggle state | `() => void` | | set | Set state | `(state: T \| U) => void` | | setLeft | Set state to `defaultValue` | `() => void` | | setRight | Set state to `reverseValue` if `reverseValue` is available. Otherwise set it to the reverse of `defaultValue` | `() => void` | # useTrackedEffect (/docs/useTrackedEffect) ## Overview A hook of useEffect that allow us to track which dependencies caused the effect to trigger. [Documentation and Examples](https://ahooks.js.org/hooks/use-trackedeffect) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTrackedEffect.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTrackedEffect.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTrackedEffect.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useTrackedEffect.json ``` A hook of useEffect that allow us to track which dependencies caused the effect to trigger. ## Examples ### Basic usage { const [count, setCount] = useState(0); const [count2, setCount2] = useState(0); useTrackedEffect( (changes) => { console.log('Index of changed dependencies: ', changes); }, [count, count2], ); return (

Please open the browser console to view the output!

Count: {count}

Count2: {count2}

); }; export default Example;`} /> ## API ```typescript useTrackedEffect( effect: (changes: [], previousDeps: [], currentDeps: []) => (void | (() => void | undefined)), deps?: deps, ) ``` The API is alike `React.useEffect`, but the first function will receive three parameters: `changes`, `previousDeps`, and `currentDeps`. * changes: Index of changed dependencies * previousDeps: Last deps * currentDeps: Current deps # useUnmount (/docs/useUnmount) ## Overview A hook that executes the function right before the component is unmounted. [Documentation and Examples](https://ahooks.js.org/hooks/use-unmount) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUnmount.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUnmount.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUnmount.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUnmount.json ``` A hook that executes the function right before the component is unmounted. ## Examples ### Default Usage { useUnmount(() => { console.info('unmount'); }); return

Hello World!

; }; const Example = () => { const [state, { toggle }] = useBoolean(true); return ( <> {state && } ); }; export default Example;`} /> ## API ```typescript useUnmount(fn: () => void); ``` ### Params | Property | Description | Type | Default | | -------- | --------------------------- | ------------ | ------- | | fn | The function to be executed | `() => void` | - | # useUnmountedRef (/docs/useUnmountedRef) ## Overview A Hook can be used to get whether the component is unmounted. [Documentation and Examples](https://ahooks.js.org/hooks/use-unmountedref) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUnmountedRef.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUnmountedRef.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUnmountedRef.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUnmountedRef.json ``` A Hook can be used to get whether the component is unmounted. ## Examples ### Default Usage { const unmountedRef = useUnmountedRef(); useEffect(() => { setTimeout(() => { if (!unmountedRef.current) { console.info('component is alive'); } }, 3000); }, []); return

Hello World!

; }; const Example = () => { const [state, { toggle }] = useBoolean(true); return ( <> {state && } ); }; export default Example;`} /> ## API ```typescript const unmountRef: { current: boolean } = useUnmountedRef(); ``` ### Result | Property | Description | Type | | ---------- | ---------------------------------- | ---------------------- | | unmountRef | Whether the component is unmounted | `{ current: boolean }` | # useUpdate (/docs/useUpdate) ## Overview A hook that returns a function which can be used to force the component to re-render. [Documentation and Examples](https://ahooks.js.org/hooks/use-update) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUpdate.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUpdate.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUpdate.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUpdate.json ``` A hook that returns a function which can be used to force the component to re-render. ## Examples ### Default Usage { const update = useUpdate(); return ( <>
Time: {Date.now()}
); }; export default Example;`} /> ## API ```typescript const update = useUpdate(); ``` # useUpdateEffect (/docs/useUpdateEffect) ## Overview A hook alike `useEffect` but skips running the effect for the first time. [Documentation and Examples](https://ahooks.js.org/hooks/use-updateeffect) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUpdateEffect.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUpdateEffect.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUpdateEffect.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUpdateEffect.json ``` A hook alike `useEffect` but skips running the effect for the first time. ## Examples ### Basic usage { const [count, setCount] = useState(0); const [effectCount, setEffectCount] = useState(0); const [updateEffectCount, setUpdateEffectCount] = useState(0); useEffect(() => { setEffectCount((c) => c + 1); }, [count]); useUpdateEffect(() => { setUpdateEffectCount((c) => c + 1); return () => { // do something }; }, [count]); // you can include deps array if necessary return (

effectCount: {effectCount}

updateEffectCount: {updateEffectCount}

); }; export default Example;`} /> ## API The API is exactly the same as `React.useEffect`. ```typescript useUpdateEffect( effect: React.EffectCallback, deps?: React.DependencyList, ) ``` # useUpdateLayoutEffect (/docs/useUpdateLayoutEffect) ## Overview A hook alike `useLayoutEffect` but skips running the effect for the first time. [Documentation and Examples](https://ahooks.js.org/hooks/use-updatelayouteffect) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUpdateLayoutEffect.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUpdateLayoutEffect.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUpdateLayoutEffect.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUpdateLayoutEffect.json ``` A hook alike `useLayoutEffect` but skips running the effect for the first time. ## Examples ### Basic usage { const [count, setCount] = useState(0); const [layoutEffectCount, setLayoutEffectCount] = useState(0); const [updateLayoutEffectCount, setUpdateLayoutEffectCount] = useState(0); useLayoutEffect(() => { setLayoutEffectCount((c) => c + 1); }, [count]); useUpdateLayoutEffect(() => { setUpdateLayoutEffectCount((c) => c + 1); return () => { // do something }; }, [count]); // you can include deps array if necessary return (

layoutEffectCount: {layoutEffectCount}

updateLayoutEffectCount: {updateLayoutEffectCount}

); }; export default Example;`} /> ## API The API is exactly the same as `React.useLayoutEffect`. ```typescript useUpdateEffect( effect: React.EffectCallback, deps?: React.DependencyList, ) ``` # useUrlState (/docs/useUrlState) ## Overview A hook alike `useLayoutEffect` but skips running the effect for the first time. [Documentation and Examples](https://ahooks.js.org/hooks/use-updatelayouteffect) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUrlState.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUrlState.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUrlState.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useUrlState.json ``` ## Examples > This hook relies on useLocation & useHistory & useNavigate from `react-router`, to use this hook, you need to ensure > > 1\. Your project is using `react-router` version 5.0 or 6.0 to manage routing > > 2\. Installed @ahooksjs/use-url-state ## Usage ```js import useUrlState from '@/src/hooks/ahooks/useUrlState'; ``` ## Examples ### CodeSandbox Demo React Router V5: [https://codesandbox.io/s/suspicious-feather-cz4e0?file=/App.tsx](https://codesandbox.io/s/suspicious-feather-cz4e0?file=/App.tsx) React Router V6: [https://codesandbox.io/s/autumn-shape-odrt9?file=/App.tsx](https://codesandbox.io/s/autumn-shape-odrt9?file=/App.tsx) ### Default usage ```tsx import React from 'react'; import useUrlState from '@/src/hooks/ahooks/useUrlState'; export default () => { const [state, setState] = useUrlState({ count: '1' }); return ( <>
state: {state?.count}
); }; ``` ### Multi-state management ```tsx import React from 'react'; import useUrlState from '@/src/hooks/ahooks/useUrlState'; export default () => { const [state, setState] = useUrlState({ page: '1', pageSize: '10' }); return ( <>
page: {state.page}

pageSize: {state.pageSize}
); }; ``` ### Multi-state management (split) ```tsx import React from 'react'; import useUrlState from '@/src/hooks/ahooks/useUrlState'; export default () => { const [page, setPage] = useUrlState({ page: '1' }); const [pageSize, setPageSize] = useUrlState({ pageSize: '10' }); return ( <>
page: {page.page}

pageSize: {pageSize.pageSize}
); }; ``` ### Custom query-string options ```tsx import React from 'react'; import useUrlState from '@/src/hooks/ahooks/useUrlState'; export default () => { const [state, setState] = useUrlState( { ids: ['1', '2', '3'] }, { parseOptions: { arrayFormat: 'comma', }, stringifyOptions: { arrayFormat: 'comma', }, }, ); return (
ids: {JSON.stringify(state.ids)}
); }; ``` ## API ```typescript const [state, setState] = useUrlState(baseState, options); ``` ### Params | Property | Description | Type | Default | | --------- | ----------------------------------------------- | -------------- | ------- | | baseState | URL search params will be merged into BaseState | `S \| () => S` | - | | options | Url config | `Options` | - | ### Options | Property | Description | Type | Default | | ---------------- | ----------------------------------------------------------------------------------------------------------- | --------------------- | -------- | | navigateMode | Type of history navigate mode | `'push' \| 'replace'` | `'push'` | | parseOptions | [parse](https://github.com/sindresorhus/query-string#parsestring-options) options of `query-string` | `ParseOptions` | - | | stringifyOptions | [stringify](https://github.com/sindresorhus/query-string#stringifyobject-options) options of `query-string` | `StringifyOptions` | - | ### Result | Property | Description | Type | | -------- | -------------------------------------------- | ------------------------------------------------- | | state | Url query object | `object` | | setState | Same as useState, but state should be object | `(state: S) => void \| (() => ((state: S) => S))` | # useVirtualList (/docs/useVirtualList) ## Overview A hook that allows you to use virtual list to render huge chunks of list data. [Documentation and Examples](https://ahooks.js.org/hooks/use-virtuallist) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useVirtualList.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useVirtualList.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useVirtualList.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useVirtualList.json ``` A hook that allows you to use virtual list to render huge chunks of list data. ## Examples ### Default usage { const containerRef = useRef(null); const wrapperRef = useRef(null); const originalList = useMemo(() => Array.from(Array(99999).keys()), []); const [list] = useVirtualList(originalList, { containerTarget: containerRef, wrapperTarget: wrapperRef, itemHeight: 60, overscan: 10, }); return ( <>
{list.map((ele) => (
Row: {ele.data}
))}
); }; export default Example;`} /> ### Dynamic item height { const containerRef = useRef(null); const wrapperRef = useRef(null); const originalList = useMemo(() => Array.from(Array(99999).keys()), []); const [value, onChange] = React.useState(0); const [list, scrollTo] = useVirtualList(originalList, { containerTarget: containerRef, wrapperTarget: wrapperRef, itemHeight: (i) => \(i \% 2 === 0 \? 42 \+ 8 \: 84 \+ 8\), overscan: 10, }); return (
onChange(Number(e.target.value))} />
{list.map((ele) => (
Row: {ele.data} size: {ele.index % 2 === 0 ? 'small' : 'large'}
))}
); }; export default Example;`} /> ## API ```typescript const [list, scrollTo] = useVirtualList( originalList: T[], options: { containerTarget: (() => Element) | Element | MutableRefObject, wrapperTarget: (() => Element) | Element | MutableRefObject, itemHeight: number | ((index: number, data: T) => number), overscan?: number, } ); ``` ### Params | Property | Description | Type | Default | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- | | originalList | The original list that contains a lot of data entries. **Attention: must undergo useMemo processing or never change, otherwise there will be a dead loop** | `T[]` | `[]` | | options | config | `Options` | - | ### Options | Property | Description | Type | Default | | --------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------- | ------- | | containerTarget | Outter Container,support DOM element or ref | `() => Element` \| `Element` \| `MutableRefObject` | - | | wrapperTarget | Inner Container,DOM element or ref | `() => Element` \| `Element` \| `MutableRefObject` | - | | itemHeight | Item height, accept a pixel value or a function that returns the height | `number` \| `((index: number, data: T) => number)` | - | | overscan | The extra buffer items outside of the view area | `number` | `5` | ### Result | Property | Description | Type | | -------- | ------------------------------------------------------ | ------------------------------ | | list | The current portion of data need to be rendered to DOM | `{ data: T, index: number }[]` | | scrollTo | Scroll to specific index | `(index: number) => void` | # useWebSocket (/docs/useWebSocket) ## Overview A hook for WebSocket. [Documentation and Examples](https://ahooks.js.org/hooks/use-websocket) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useWebSocket.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useWebSocket.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useWebSocket.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useWebSocket.json ``` A hook for WebSocket. ## Examples ### Default usage { const messageHistory = useRef([]); const { readyState, sendMessage, latestMessage, disconnect, connect } = useWebSocket( 'wss://ws.postman-echo.com/raw', ); messageHistory.current = useMemo( () => messageHistory.current.concat(latestMessage), [latestMessage], ); return (
{/* send message */} {/* disconnect */} {/* connect */}
readyState: {readyState}

received message:

{messageHistory.current.map((message, index) => (

{message?.data}

))}
); }; export default Example;`} /> ## API ```typescript enum ReadyState { Connecting = 0, Open = 1, Closing = 2, Closed = 3, } interface Options { reconnectLimit?: number; reconnectInterval?: number; onOpen?: (event: WebSocketEventMap['open'], instance: WebSocket) => void; onClose?: (event: WebSocketEventMap['close'], instance: WebSocket) => void; onMessage?: (message: WebSocketEventMap['message'], instance: WebSocket) => void; onError?: (event: WebSocketEventMap['error'], instance: WebSocket) => void; protocols?: string | string[]; } interface Result { latestMessage?: WebSocketEventMap['message']; sendMessage: WebSocket['send']; disconnect: () => void; connect: () => void; readyState: ReadyState; webSocketIns?: WebSocket; } useWebSocket(socketUrl: string, options?: Options): Result; ``` ### Params | Property | Description | Type | Default | | --------- | ------------------------------ | --------- | ------- | | socketUrl | Required, webSocket url | `string` | - | | options | connect the configuration item | `Options` | - | #### Options | Options Property | Description | Type | Default | | ----------------- | ---------------------------------- | ---------------------------------------------------------------------- | ------- | | onOpen | The webSocket connect callback | `(event: WebSocketEventMap['open'], instance: WebSocket) => void` | - | | onClose | WebSocket close callback | `(event: WebSocketEventMap['close'], instance: WebSocket) => void` | - | | onMessage | WebSocket receive message callback | `(message: WebSocketEventMap['message'], instance: WebSocket) => void` | - | | onError | WebSocket error callback | `(event: WebSocketEventMap['error'], instance: WebSocket) => void` | - | | reconnectLimit | Retry times | `number` | `3` | | reconnectInterval | Retry interval(ms) | `number` | `3000` | | manual | Manually starts connection | `boolean` | `false` | | protocols | Sub protocols | `string` \| `string[]` | - | ### Result | Options Property | Description | Type | | ---------------- | -------------------------------------------------------------------------------------- | ------------------------------ | | latestMessage | Latest message | `WebSocketEventMap['message']` | | sendMessage | Send message function | `WebSocket['send']` | | disconnect | Disconnect webSocket manually | `() => void` | | connect | Connect webSocket manually. If already connected, close the current one and reconnect. | `() => void` | | readyState | Current webSocket connection status | `ReadyState` | | webSocketIns | WebSocket instance | `WebSocket` | # useWhyDidYouUpdate (/docs/useWhyDidYouUpdate) ## Overview Help developers troubleshoot what changes have caused component rerender. [Documentation and Examples](https://ahooks.js.org/hooks/use-whydidyouupdate) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useWhyDidYouUpdate.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useWhyDidYouUpdate.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useWhyDidYouUpdate.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useWhyDidYouUpdate.json ``` Help developers troubleshoot what changes have caused component rerender. ## Examples ### Default usage = (props) => { const [randomNum, setRandomNum] = useState(Math.random()); useWhyDidYouUpdate('useWhyDidYouUpdateComponent', { ...props, randomNum }); return (
number: {props.count}
randomNum: {randomNum}
); }; const Example = () => { const [count, setCount] = useState(0); return (

Please open the browser console to view the output!

); }; export default Example;`} /> ## API ```typescript type IProps = Record; useWhyDidYouUpdate(componentName: string, props: IProps): void; ``` ### Params | Property | Description | Type | Default | | ------------- | ------------------------------------------------------------------------------------------- | -------- | ------- | | componentName | Required, the name of the observation component | `string` | - | | props | Required, data to be observed (`state` or `props` and other data that may lead to rerender) | `object` | - | ### Result Please open the browser console, you can see the output of the changed observed `state` or `props`. # useCallbackEvent (/docs/external-hooks/useCallbackEvent) # useCallBackEvent A hook that ensures callback functions always reference the latest version without causing component re-renders, similar to React's experimental `useEffectEvent`. ## Features * ✅ Always calls the latest callback function * 🎯 Stable function reference (doesn't change between renders) * 🚀 Prevents unnecessary re-renders in child components * 🔄 Solves closure issues with callbacks ## When to Use * Event handlers passed to memoized child components * Callbacks in `useEffect` that need access to latest state * Functions passed to third-party libraries or event listeners * Avoiding stale closure problems ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCallbackEvent.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCallbackEvent.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCallbackEvent.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useCallbackEvent.json ``` ## Usage { console.log('ExpensiveChild rendered!'); return ; }); const Example = () => { const [count, setCount] = useState(0); // The callback always has access to the latest count // but the function reference never changes const handleClick = useCallbackEvent(() => { console.log('Current count:', count); }); return <>

Count: {count}

; }; export default Example;`} /> ## Examples ### Basic Usage - Solving Stale Closure { const [count, setCount] = useState(0); // ❌ Wrong: This will always log 0 because of stale closure const handleClickWrong = useCallback(() => { setTimeout(() => { console.log('Wrong count:', count); // Always 0! }, 3000); }, []); // Empty deps means it captures count = 0 // ✅ Correct: This will always log the latest count const handleClickCorrect = useCallbackEvent(() => { setTimeout(() => { console.log('Correct count:', count); // Always latest! }, 3000); }); return (

Count: {count}

Click increment a few times, then click one of the log buttons

); }; export default Example;`} /> ### Preventing Re-renders with Memoized Children { console.log('ExpensiveChild rendered!'); return ; }); const Example = () => { const [count, setCount] = useState(0); const [message, setMessage] = useState('Hello'); // ❌ Without useCallbackEvent: Child re-renders when message changes const handleWithUseCallback = useCallback(() => { console.log('Count:', count, 'Message:', message); }, [count, message]); // Dependencies cause re-creation // ✅ With useCallbackEvent: Child never re-renders const handleWithCallbackEvent = useCallbackEvent(() => { console.log('Count:', count, 'Message:', message); }); // Stable reference, always latest values return (

Count: {count}

Message: {message}

Open console to see when ExpensiveChild re-renders

); }; export default Example;`} /> ### With Event Listeners { const [position, setPosition] = useState({ x: 0, y: 0 }); const [color, setColor] = useState('blue'); // Always has access to latest color without re-adding listener const handleMouseMove = useCallbackEvent((e: MouseEvent) => { setPosition({ x: e.clientX, y: e.clientY }); console.log('Current color:', color); // Always latest! }); useEffect(() => { window.addEventListener('mousemove', handleMouseMove); return () => window.removeEventListener('mousemove', handleMouseMove); }, []); // Empty deps - listener never re-added! return (

Mouse position: X: {position.x}, Y: {position.y}

Current color: {color}

Move your mouse around. The callback sees the latest color even though the event listener was only added once!

); }; export default Example;`} /> ### With Third-Party Libraries { const [count, setCount] = useState(0); const [logs, setLogs] = useState([]); // Simulating a third-party library that stores callbacks const libraryRef = useRef({ callbacks: [] as Function[], registerCallback(cb: Function) { this.callbacks.push(cb); }, executeCallbacks() { this.callbacks.forEach(cb => cb()); } }); const handleEvent = useCallbackEvent(() => { const log = \`Event triggered! Count: \${count}\`; setLogs(prev => [...prev, log]); }); useEffect(() => { // Register callback only once with the library libraryRef.current.registerCallback(handleEvent); }, []); // handleEvent is stable, so this only runs once return (

Count: {count}

Logs:

{logs.map((log, i) => (
{log}
))}

Increment the count, then trigger callbacks. The callback sees the latest count even though it was registered only once!

); }; export default Example;`} /> ## API ```typescript const stableCallback = useCallbackEvent(callback: T): T ``` ### Params | Property | Description | Type | Required | | -------- | ----------------------------- | ------------------------- | -------- | | callback | The callback function to wrap | `(...args: any[]) => any` | Yes | ### Result | Property | Description | Type | | -------------- | ----------------------------------------------------------------- | ------------------------- | | stableCallback | A stable function reference that always calls the latest callback | `(...args: any[]) => any` | ## Comparison with Other Approaches ### vs `useCallback` ```tsx // useCallback: Need to include all dependencies const callback = useCallback(() => { console.log(stateA, stateB, stateC); }, [stateA, stateB, stateC]); // Re-creates when any dep changes // useCallbackEvent: Always stable, always latest const callback = useCallbackEvent(() => { console.log(stateA, stateB, stateC); }); // Never re-creates ``` ### vs `useRef` ```tsx // useRef: Manual management, verbose const callbackRef = useRef(callback); useEffect(() => { callbackRef.current = callback; }, [callback]); const stableCallback = useCallback((...args) => { return callbackRef.current(...args); }, []); // useCallbackEvent: Simple and clean const stableCallback = useCallbackEvent(callback); ``` ## How It Works 1. **Stores Latest Callback**: Uses `useImperativeHandle` to store the current callback 2. **Stable Wrapper**: Returns a memoized function (via `useCallback` with empty deps) 3. **Latest Execution**: The wrapper always calls the stored latest callback 4. **No Re-creation**: The returned function reference never changes ## Notes * This is similar to React's experimental `useEffectEvent` hook (not yet stable) * The returned function reference is stable and won't cause re-renders * The callback always has access to the latest props, state, and context * Perfect for event handlers, callbacks in effects, and third-party library integrations * Throws an error if called when the callback reference is null (edge case protection) ## TypeScript ```typescript function useCallbackEvent unknown>( callback: T ): (...args: Parameters) => ReturnType; ``` The hook is fully typed and preserves the callback's parameter and return types. # useScrollLocker (/docs/external-hooks/useScrollLocker) # useScrollLocker A hook that locks the body scroll to prevent page scrolling, commonly used for modals, drawers, and popup components. ## Features * 🔒 Locks body scrolling when enabled * 📏 Automatically compensates for scrollbar width to prevent layout shift * 🧹 Cleans up styles when unmounted or lock is disabled * 🎯 Uses unique IDs to support multiple instances ## When to Use * Modal dialogs and popups * Drawer/Sidebar components * Full-screen overlays * Any component that needs to prevent background scrolling ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useScrollLocker.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useScrollLocker.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useScrollLocker.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useScrollLocker.json ``` ## Usage ```tsx import { useScrollLocker } from 'ahooks'; function Modal({ visible }) { // Lock scroll when modal is visible useScrollLocker(visible); if (!visible) return null; return (
Modal Content
); } ``` ## Examples ### Basic Usage ```tsx import React, { useState } from 'react'; import { useScrollLocker } from 'ahooks'; export default () => { const [isLocked, setIsLocked] = useState(false); useScrollLocker(isLocked); return (

Scroll status: {isLocked ? '🔒 Locked' : '🔓 Unlocked'}

Try scrolling the page...

); }; ``` ### With Modal Component ```tsx import React, { useState } from 'react'; import { useScrollLocker } from 'ahooks'; function Modal({ visible, onClose, children }) { useScrollLocker(visible); if (!visible) return null; return (
e.stopPropagation()} > {children}
); } export default () => { const [visible, setVisible] = useState(false); return (

Scroll down to see more content...

setVisible(false)}>

Modal Title

This is a modal with locked background scroll.

Try scrolling - the background won't move!

); }; ``` ## API ```typescript useScrollLocker(lock?: boolean): void ``` ### Params | Property | Description | Type | Default | | -------- | -------------------------------------------------------------------- | --------- | ------- | | lock | Whether to lock the scroll. When `true`, body scrolling is disabled. | `boolean` | `false` | ### How It Works 1. **Scroll Detection**: Checks if the body content overflows the viewport 2. **Scrollbar Compensation**: Measures the scrollbar width and adds padding to prevent layout shift 3. **Style Injection**: Dynamically injects CSS to hide overflow and compensate for scrollbar 4. **Cleanup**: Automatically removes injected styles when lock is disabled or component unmounts ### Implementation Details The hook: * Uses `useLayoutEffect` to synchronously apply styles before browser paint * Generates a unique ID for each instance to avoid conflicts * Applies `overflow-y: hidden` to the body * Calculates and compensates for scrollbar width to prevent layout shift * Supports multiple concurrent locks (useful for nested modals) ## Notes * The hook uses `useLayoutEffect` to ensure styles are applied synchronously before the browser paints * Each hook instance gets a unique ID, so multiple instances can coexist * The scrollbar width is calculated dynamically to support different browsers and operating systems * Width compensation only applies when the body is actually overflowing ## TypeScript ```typescript function useScrollLocker(lock?: boolean): void; ``` # Basic usage (/docs/useRequest/basic) # Basic usage In this section, we will introduce the core and basic functionalities of `useRequest`, that is, the functionalities of the `useRequest` kernel. ## Default request By default, the first parameter of `useRequest` is an asynchronous function, which is automatically executed when the component is initialized. At the same time, it automatically manages the status of `loading`, `data`, `error` of the asynchronous function. ```js const { data, error, loading } = useRequest(service); ```
{ return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve('John Doe'); } else { reject(new Error('Failed to get username')); } }, 1000); }); } const Example = () => { const { data, error, loading } = useRequest(getUsername); if (error) { return
{error.message}
; } if (loading) { return
loading...
; } return
Username: {data}
; }; export default Example;`} /> ## Manually trigger If `options.manual = true` is set, `useRequest` will not be executed by default, and the execution needs to be triggered by `run` or `runAsync`. ```tsx | pure const { loading, run, runAsync } = useRequest(service, { manual: true }); ``` The difference between `run` and `runAsync` is: * `run` is a normal synchronous function, we will automatically catch the exception, you can use `options.onError` to handle the behavior of the exception. * `runAsync` is a asynchronous function that returns a `Promise`. If you use `runAsync` to call it, it means you need to catch the exception yourself. ```ts runAsync().then((data) => { console.log(data); }).catch((error) => { console.log(error); }) ``` Next, we will demonstrate the difference between `run` and `runAsync` through the simple scenario of editing the username. In this example, we use run(username) to edit the username, and use onSuccess and onError to handle success and failure. { return new Promise((resolve) => { setTimeout(() => { resolve({ success: true }); }, 1000); }); } const Example = () => { const [state, setState] = useState(''); const { loading, run } = useRequest(changeUsername, { manual: true, onSuccess: (result, params) => { if (result.success) { setState(''); console.log(\`Username changed to: \${params[0]}\`); } }, }); return (
setState(e.target.value)} value={state} placeholder="Please enter username" style={{ width: 240, marginRight: 16 }} />
); }; export default Example;`} /> In this example, we use runAsync(username) to edit the user name. At this time, we must catch the exception through catch. { return new Promise((resolve) => { setTimeout(() => { resolve({ success: true }); }, 1000); }); } const Example = () => { const [state, setState] = useState(''); const { loading, runAsync } = useRequest(changeUsername, { manual: true }); const onClick = async () => { try { await runAsync(state); setState(''); console.log(\`Username changed to: \${state}\`); } catch (error) { console.log(error.message); } }; return (
setState(e.target.value)} value={state} placeholder="Please enter username" style={{ width: 240, marginRight: 16 }} />
); }; export default Example;`} /> ## The life cycle `useRequest` provides the following life cycle for you to do some processing in different stages of asynchronous functions. * `onBefore`: Triggered before the request * `onSuccess`: Triggered when the request is resolved * `onError`: Triggered when the request is rejected * `onFinally`: Triggered when the request is completed { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve(); } else { reject(new Error('Failed to modify username')); } }, 1000); }); } const Example = () => { const [state, setState] = useState(''); const { loading, run } = useRequest(editUsername, { manual: true, onBefore: (params) => { console.info(\`Start Request: \${params[0]}\`); }, onSuccess: (result, params) => { setState(''); console.log(\`The username was changed to "\${params[0]}" !\`); }, onError: (error) => { console.error(error.message); }, onFinally: (params, result, error) => { console.info(\`Request finish\`); }, }); return (
setState(e.target.value)} value={state} placeholder="Please enter username" style={{ width: 240, marginRight: 16 }} />
); }; export default Example;`} /> ## Refresh (repeat the last request) `useRequest` provides the `refresh` and `refreshAsync` methods so that we can use the last parameters to re-run the request. If in the scenario of reading user information 1. We read the user information with ID 1 `run(1)` 2. We updated user information by some ways 3. We want to re-initiate the last request, then we can use `refresh` instead of `run(1)`, which is very useful in scenarios with complex parameters { console.log('use-request-refresh-id', id); return new Promise((resolve) => { setTimeout(() => { resolve(Mock.mock('@name')); }, 1000); }); } const Example = () => { const { data, loading, run, refresh } = useRequest((id: number) => getUsername(id), { manual: true, }); useEffect(() => { run(1); }, []); if (loading) { return
loading...
; } return (

Username: {data}

); }; export default Example;`} /> Of course, the difference between `refresh` and `refreshAsync` is the same as `run` and `runAsync`. ## Change data immediately `useRequest` provides `mutate`, which can immediate modify the `data`. The usage of `mutate` is consistent with `React.setState`, supports: `mutate(newData)` and `mutate((oldData) => newData)`. In the following example, we demonstrate a scenario of `mutate`. We have modified the user name, but we do not want to wait for the request to be successful before giving feedback to the user. Instead, modify the data directly, then call the modify request in background, and provide additional feedback after the request returns. { return new Promise((resolve) => { setTimeout(() => { resolve(Mock.mock('@name')); }, 1000); }); } function editUsername(username: string): Promise { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve(); } else { reject(new Error('Failed to modify username')); } }, 1000); }); } const Example = () => { // store last username const lastRef = useRef(); const [state, setState] = useState(''); // get username const { data: username, mutate } = useRequest(getUsername); // edit username const { run: edit } = useRequest(editUsername, { manual: true, onSuccess: (result, params) => { setState(''); console.log(\`The username was changed to "\${params[0]}" !\`); }, onError: (error) => { console.error(error.message); mutate(lastRef.current); }, }); const onChange = () => { lastRef.current = username; mutate(state); edit(state); }; return (

Username: {username}

setState(e.target.value)} value={state} placeholder="Please enter username" style={{ width: 240, marginRight: 16 }} />
); }; export default Example;`} /> ## Cancel response `useRequest` provides a `cancel` function, which will **ignore** the data and error returned by the current promise **Note: Calling `cancel` doesn't cancel the execution of promise** At the same time, `useRequest` will automatically ignore the response at the following timing: * When the component is unmounting, the ongoing promise * Race cancellation, when the previous promise has not returned, if the next promise is initiated, the previous promise will be ignored { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve(); } else { reject(new Error('Failed to modify username')); } }, 1000); }); } const Example = () => { const [state, setState] = useState(''); const { loading, run, cancel } = useRequest(editUsername, { manual: true, onSuccess: (result, params) => { setState(''); console.log(\`The username was changed to "\${params[0]}" !\`); }, onError: (error) => { console.error(error.message); }, }); return (
setState(e.target.value)} value={state} placeholder="Please enter username" style={{ width: 240, marginRight: 16 }} />
); }; export default Example;`} /> ## Parameter management The `params` returned by `useRequest` will record the parameters of `service`. For example, if you trigger `run(1, 2, 3)`, then `params` is equal to `[1, 2, 3]`. If we set `options.manual = false`, the parameters of calling `service` for the first time can be set by `options.defaultParams`. { return new Promise((resolve) => { setTimeout(() => { resolve(Mock.mock('@name')); }, 1000); }); } const Example = () => { const [state, setState] = useState(''); // get username const { data: username, run, params, } = useRequest(getUsername, { defaultParams: ['1'], }); const onChange = () => { run(state); }; return (
setState(e.target.value)} value={state} placeholder="Please enter userId" style={{ width: 240, marginRight: 16 }} />

UserId: {params[0]}

Username: {username}

); }; export default Example;`} /> ## API ```ts const { loading: boolean, data?: TData, error?: Error, params: TParams || [], run: (...params: TParams) => void, runAsync: (...params: TParams) => Promise, refresh: () => void, refreshAsync: () => Promise, mutate: (data?: TData | ((oldData?: TData) => (TData | undefined))) => void, cancel: () => void, } = useRequest( service: (...args: TParams) => Promise, { manual?: boolean, defaultParams?: TParams, onBefore?: (params: TParams) => void, onSuccess?: (data: TData, params: TParams) => void, onError?: (e: Error, params: TParams) => void, onFinally?: (params: TParams, data?: TData, e?: Error) => void, } ); ``` ### Result | Property | Description | Type | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | data | Data returned by service | `TData` \| `undefined` | | error | Exception thrown by service | `Error` \| `undefined` | | loading | Is the service being executed | `boolean` | | params | An array of parameters for the service being executed. For example, you triggered `run(1, 2, 3)`, then params is equal to `[1, 2, 3]` | `TParams` \| `[]` | | run |
  • Manually trigger the execution of the service, and the parameters will be passed to the service
  • Automatic handling of exceptions, feedback through `onError`
| `(...params : TParams) => void` | | runAsync | The usage is the same as `run`, but it returns a Promise, so you need to handle the exception yourself. | `(...params: TParams) => Promise` | | refresh | Use the last params, call `run` again | `() => void` | | refreshAsync | Use the last params, call `runAsync` again | `() => Promise` | | mutate | Mutate `data` directly | `(data?: TData / ((oldData?: TData) => (TData / undefined))) => void` | | cancel | Ignore the current promise response | `() => void` | ### Options | Property | Description | Type | Default | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ------- | | manual |
  • The default is `false`. That is, the service is automatically executed during initialization.
  • If set to `true`, you need to manually call `run` or `runAsync` to trigger execution.
| `boolean` | `false` | | defaultParams | The parameters passed to the service at the first default execution | `TParams` | - | | onBefore | Triggered before service execution | `(params: TParams) => void` | - | | onSuccess | Triggered when service resolve | `(data: TData, params: TParams) => void` | - | | onError | Triggered when service reject | `(e: Error, params: TParams) => void` | - | | onFinally | Triggered when service execution is complete | `(params: TParams, data?: TData, e?: Error) => void` | - | Above we have introduced the most basic functionalities of useRequest, and then we will introduce some more advanced functionalities. # Cache & SWR (/docs/useRequest/cache) # Cache & SWR If `options.cacheKey` is set, `useRequest` will cache the successful data . The next time the component is initialized, if there is cached data, we will return the cached data first, and then send a new request in background, which is the ability of SWR. You can set the data retention time through `options.staleTime`. During this time, we consider the data to be fresh and will not re-initiate the request. You can also set the data cache time through `options.cacheTime`, after this time, we will clear the cached data. Next, through a few examples to experience these features. ### SWR In the following example, we set the `cacheKey`. When the component is loaded for the second time, the cached content will be returned first, and then the request will be re-run in background. You can experience the effect by clicking the button. { return new Promise<{ data: string; time: number }>((resolve) => { setTimeout(() => { resolve({ data: Mock.mock('@paragraph'), time: Date.now(), }); }, 1000); }); }; const Article: React.FC = () => { const { data, loading } = useRequest(getArticle, { cacheKey: 'cacheKey-demo', }); if (!data && loading) { return

Loading

; } return ( <>

Background loading: {loading ? 'true' : 'false'}

Latest request time: {data?.time}

{data?.data}

); }; const Example = () => { const [state, { toggle }] = useBoolean(); return (
{state &&
}
); }; export default Example;`} /> ### Keep your data fresh By setting `staleTime`, we can specify the data retention time, during which time the request will not be re-run. The following example sets a fresh time of 5s, you can experience the effect by clicking the button { return new Promise<{ data: string; time: number }>((resolve) => { setTimeout(() => { resolve({ data: Mock.mock('@paragraph'), time: Date.now(), }); }, 1000); }); }; const Article: React.FC = () => { const { data, loading } = useRequest(getArticle, { cacheKey: 'staleTime-demo', staleTime: 5000, }); if (!data && loading) { return

Loading

; } return ( <>

Background loading: {loading ? 'true' : 'false'}

Latest request time: {data?.time}

{data?.data}

); }; const Example = () => { const [state, { toggle }] = useBoolean(); return (
{state &&
}
); }; export default Example;`} /> ### Data sharing > Note: If no new request is issued, the "Data sharing" will not be triggered. `cacheTime` and `staleTime` parameters will invalidate "Data sharing". [#2313](https://github.com/alibaba/hooks/issues/2313) The content of the same `cacheKey` is shared globally, which will bring the following features: * Sharing request `Promise`: Only one of the same `cacheKey` will initiate a request at the same time, and the subsequent ones will share the same request `Promise`. * Data synchronization: When a request is made by one `cacheKey`, the contents of other identical `cacheKey` will be synchronized accordingly. In the following example, the two components will only initiate one request during initialization. And the content of the two articles is always synchronized. { console.log('cacheKey-share'); return new Promise<{ data: string; time: number }>((resolve) => { setTimeout(() => { resolve({ data: Mock.mock('@paragraph'), time: Date.now(), }); }, 3000); }); }; const Article = () => { const { data, loading, refresh } = useRequest(getArticle, { cacheKey: 'cacheKey-share', }); if (!data && loading) { return

Loading

; } return ( <>

Background loading: {loading ? 'true' : 'false'}

Latest request time: {data?.time}

{data?.data}

); }; const Example = () => { return (

Article 1

Article 2

); }; export default Example;`} /> ### Parameters cache The cached data includes `data` and `params`. Through the `params` caching mechanism, we can remember the conditions of the last request and initialize it next time. In the following example, we can initialize the `keyword` from the cached `params` { console.log('cacheKey', keyword); return new Promise<{ data: string; time: number }>((resolve) => { setTimeout(() => { resolve({ data: Mock.mock('@paragraph'), time: Date.now(), }); }, 1000); }); }; const Article = () => { const { data, params, loading, run } = useRequest(getArticle, { cacheKey: 'cacheKey-demo', }); const [keyword, setKeyword] = useState(params[0] || ''); if (!data && loading) { return

Loading

; } return ( <>
setKeyword(e.target.value)} />

Background loading: {loading ? 'true' : 'false'}

Latest request time: {data?.time}

Keyword: {keyword}

{data?.data}

); }; const Example = () => { const [state, { toggle }] = useBoolean(); return (
{state &&
}
); }; export default Example;`} /> ### Clear cache ahooks provides a `clearCache` method, which can clear the cache data of the specified `cacheKey`. { return new Promise<{ data: string; time: number }>((resolve) => { setTimeout(() => { resolve({ data: Mock.mock('@paragraph'), time: Date.now(), }); }, 3000); }); }; const Article = ({ cacheKey }) => { const { data, loading } = useRequest(getArticle, { cacheKey, }); if (!data && loading) { return

Loading

; } return ( <>

Background loading: {loading ? 'true' : 'false'}

Latest request time: {data?.time}

{data?.data}

); }; const clear = (cacheKey?: string | string[]) => { clearCache(cacheKey); const tips = Array.isArray(cacheKey) ? cacheKey.join('、') : cacheKey; console.log(\`Clear \${tips ?? 'All'} finished\`); }; const Example = () => { const [state, { toggle }] = useBoolean(); return (

Article 1

{state &&
}

Article 2

{state &&
}

Article 3

{state &&
}
); }; export default Example;`} /> ### Custom cache By setting `setCache` and `getCache`, you can customize the cache, for example, you can store data in `localStorage`, `IndexDB`, etc. Please note: 1. `setCache` and `getCache` need to be used together. 2. In the custom cache mode, `cacheTime` and `clearCache` will be unused, please implement it yourself according to the actual situation. { return new Promise<{ data: string; time: number }>((resolve) => { setTimeout(() => { resolve({ data: Mock.mock('@paragraph'), time: Date.now(), }); }, 1000); }); }; const cacheKey = 'setCache-demo'; const Article: React.FC = () => { const { data, loading } = useRequest(getArticle, { cacheKey, setCache: (value) => localStorage.setItem(cacheKey, JSON.stringify(value)), getCache: () => JSON.parse(localStorage.getItem(cacheKey) || '{}'), }); if (!data && loading) { return

Loading

; } return ( <>

Background loading: {loading ? 'true' : 'false'}

Latest request time: {data?.time}

{data?.data}

); }; const Example = () => { const [state, { toggle }] = useBoolean(); return (
{state &&
}
); }; export default Example;`} /> ## API ```ts interface CachedData { data: TData; params: TParams; time: number; } ``` ### Options | Property | Description | Type | Default | | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | -------- | | cacheKey | A unique ID of the request. Data of the same `cacheKey` will synchronized globally (`cacheTime` and `staleTime` parameters will invalidate this mechanism, see demo: [Data sharing](#data-sharing)) | `string` | - | | cacheTime |
  • Set the cache time. By default, the cached data will be cleared after 5 minutes.
  • If set to `-1`, the cached data will never expire
| `number` | `300000` | | staleTime |
  • Time to consider the cached data is fresh. Within this time interval, the request will not be re-initiated
  • If set to `-1`, it means that the data is always fresh
| `number` | `0` | | setCache |
  • Custom set cache
  • `setCache` and `getCache` need to be used together
  • In the custom cache mode, `cacheTime` and `clearCache` are useless, please implement it yourself according to the actual situation.
| `(data: CachedData) => void;` | - | | getCache | Custom get cache | `(params: TParams) => CachedData` | - | ### clearCache ```tsx | pure import { clearCache } from 'ahooks'; clearCache(cacheKey?: string | string[]); ``` 1. Support clearing a single cache, or a group of caches 2. If `cacheKey` is empty, all cached data will be cleared ## Remark * Only successful request data will be cached * Cached data includes `data` and `params` # Debounce (/docs/useRequest/debounce) # Debounce Enter the debounce mode by setting `options.debounceWait`. At this time, if `run` or `runAsync` is triggered frequently, the request will be executed with the debounce strategy. ```tsx | pure const { data, run } = useRequest(getUsername, { debounceWait: 300, manual: true }); ``` As in the example code above, if `run` is triggered frequently, it will only wait for 300ms to execute after the last trigger. You can quickly enter text in the input box below to experience the effect { console.log('debounce getEmail', search); return new Promise((resolve) => { setTimeout(() => { resolve(Mock.mock({ 'data|5': ['@email'] }).data); }, 300); }); } const Example = () => { const { data, loading, run } = useRequest(getEmail, { debounceWait: 1000, manual: true, }); return (
run(e.target.value)} /> {loading ? (

loading

) : (
    {data?.map((i) => (
  • {i}
  • ))}
)}
); }; export default Example;`} /> ## API ### Options The usage and effect of all debounce property are the same as [lodash.debounce](https://lodash.com/docs/4.17.15#debounce) | Property | Description | Type | Default Value | | ------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------- | ------------- | | debounceWait | Debounce delay time, in milliseconds. After setting, enter the debounce mode | `number` | - | | debounceLeading | Execute the request before the delay starts | `boolean` | `false` | | debounceTrailing | Execute the request after the delay ends | `boolean` | `true` | | debounceMaxWait | The maximum time request is allowed to be delayed before it’s executed | `number` | - | | pollingIntervalWhen | pollingIntervalWhen is used together with debounce options, it specifies when to start polling | `(data, params) => number \| boolean` | - | ## Remark * `options.debounceWait`, `options.debounceLeading`, `options.debounceTrailing`, `options.debounceMaxWait`, `options.pollingIntervalWhen` support dynamic changes. * `runAsync` will return a `Promise` when it is actually executed. When it is not executed, there will be no return. * `cancel` can abort a function waiting to be executed. # Quick Start (/docs/useRequest) ## Overview * `useRequest` is a powerful React hook for managing data fetching and state in your applications. It simplifies the process of making API requests, handling loading states, caching, and error management, allowing developers to focus on building features rather than boilerplate code. * [Documentation and Examples](https://ahooks.js.org/hooks/use-request) ## Installation ```bash pnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRequest.json ``` ```bash npx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRequest.json ``` ```bash yarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRequest.json ``` ```bash bun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useRequest.json ``` ## Usage # Quick Start `useRequest` is a powerful Hooks for asynchronous data management. `useRequest` is sufficient enough for network request scenarios in React projects. `useRequest` organizes code through a plug-in pattern, the core code is extremely simple, and can be easily extended for more advanced features. Current features include: * Automatic/manual request * Polling * Debounce * Throttle * Refresh on window focus * Error retry * Loading delay * SWR(stale-while-revalidate) * Caching Next, let's get to know `useRequest` from the two simplest examples. ## Default usage The first parameter of `useRequest` is an asynchronous function, which will be automatically triggered when the component is first loaded. At the same time, it automatically manages the status of `loading`, `data`, `error` of the asynchronous function. ```js const { data, error, loading } = useRequest(getUsername); ```
{ return new Promise((resolve) => { setTimeout(() => { resolve(Mock.mock('@name')); }, 1000); }); } const Example = () => { const { data, error, loading } = useRequest(getUsername); if (error) { return
failed to load
; } if (loading) { return
loading...
; } return
Username: {data}
; }; export default Example;`} /> ## Manual trigger If `options.manual = true` is set, useRequest will not be executed by default, and the execution needs to be triggered by `run`. ```js const { loading, run } = useRequest(changeUsername, { manual: true }); ```
{ return new Promise((resolve) => { setTimeout(() => { resolve({ success: true }); }, 1000); }); } const Example = () => { const [state, setState] = useState(''); const { loading, run } = useRequest(changeUsername, { manual: true, onSuccess: (result, params) => { if (result.success) { setState(''); console.log(\`Username changed to: \${params[0]}\`); } }, }); return (
setState(e.target.value)} value={state} placeholder="Please enter username" style={{ width: 240, marginRight: 16 }} />
); }; export default Example;`} /> In the above two examples, we demonstrated the most basic usages of `useRequest`. Next, we will introduce the features of `useRequest` one by one. # Loading Delay (/docs/useRequest/loading-delay) ## Loading Delay By setting `options.loadingDelay`, you can delay the time when `loading` turns to `true`, effectively prevent UI flashing. ```tsx | pure const { loading, data } = useRequest(getUsername, { loadingDelay: 300 }); return
{ loading ? 'Loading...' : data }
``` For example, in the above scenario, if `getUsername` returns within 300ms, `loading` will not become `true`, avoiding the page displays `Loading...`. You can quickly click the button in the example below to experience the effect { return new Promise((resolve) => { setTimeout(() => { resolve('H' + Math.random().toString(36).substring(7)); }, 200); }); } const Example = () => { const action = useRequest(getUsername); const withLoadingDelayAction = useRequest(getUsername, { loadingDelay: 300, }); const trigger = () => { action.run(); withLoadingDelayAction.run(); }; return (
Username: {action.loading ? 'Loading...' : action.data}
Username: {withLoadingDelayAction.loading ? 'Loading...' : withLoadingDelayAction.data}
); }; export default Example;`} /> ## API | Property | Description | Type | Default | | ------------ | ------------------------------------------------- | -------- | ------- | | loadingDelay | Set the delay time for `loading` to become `true` | `number` | `0` | ## Remark `options.loadingDelay` supports dynamic changes. # Polling (/docs/useRequest/polling) ## Polling By setting `options.pollingInterval`, enter the polling mode, `useRequest` will periodically trigger service execution. ```tsx | pure const { data, run, cancel } = useRequest(getUsername, { pollingInterval: 3000, }); ``` For example, in the above scenario, `getUsername` will be requested every 3000ms. You can stop polling by `cancel` and start polling by `run/runAsync`. You can experience the effect through the following example { console.log('polling getUsername'); return new Promise((resolve) => { setTimeout(() => { resolve('H' + Math.random().toString(36).substring(7)); }, 1000); }); } const Example = () => { const { data, loading, run, cancel } = useRequest(getUsername, { pollingInterval: 1000, pollingWhenHidden: false, }); return ( <>

Username: {loading ? 'Loading' : data}

); }; export default Example;`} /> ## Polling error retry Polling by `options. PollingErrorRetryCount` configuration error retry count. ```tsx | pure const { data, run, cancel } = useRequest(getUsername, { pollingInterval: 3000, pollingErrorRetryCount: 3, }); ``` You can experience the effect through the following example. { setTimeout(() => { reject(new Error(Math.random().toString(36).substring(7))); }, 1000); }); } const Example = () => { const { data, loading, run, cancel } = useRequest(getUsername, { pollingInterval: 1000, pollingWhenHidden: false, pollingErrorRetryCount: 3, manual: true, onError: (error) => { console.log(error.message); }, }); return ( <>

Username: {loading ? 'Loading' : data}

); }; export default Example;`} /> ## API ### Return | Property | Description | Type | | -------- | ------------- | ---------------------------------------- | | run | Start polling | `(...params: TParams) => void` | | runAsync | Start polling | `(...params: TParams) => Promise` | | cancel | Stop polling | `() => void` | ### Options | Property | Description | Type | Default | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | ------- | | pollingInterval | Polling interval, in milliseconds. If the value is greater than 0, the polling mode is activated. | `number` | `0` | | pollingWhenHidden | Whether to continue polling when the page is hidden. If set to false, polling will be temporarily paused when the page is hidden, and resume when the page is visible again. | `boolean` | `true` | | pollingErrorRetryCount | Number of polling error retries. If set to -1, an infinite number of times | `number` | `-1` | | pollingIntervalWhen | Change the polling interval dynamically based on the result of the request. | `(data: TData, error: Error) => number` | - | ## Remark * `options.pollingInterval`, `options.pollingWhenHidden` support dynamic changes. * If you set `options.manual = true`, the initialization will not start polling, you need start it by `run/runAsync`. * If the `pollingInterval` changes from 0 to a value greater than 0, polling will not start automatically, and you need start it by `run/runAsync`. * The polling logic is to wait for `pollingInterval` time after each request is completed, and then initiate the next request. # Ready (/docs/useRequest/ready) ## Ready By setting `options.ready`, you can control whether a request is sent. When its value is `false`, the request will never be sent. The specific behavior is as follows: 1. In the automatic mode of `manual=false`, every time `ready` changes from `false` to `true`, a request will be automatically executed with the parameter `options.defaultParams`. 2. When `manual=true` manual request mode, as long as `ready=false`, the request triggered by `run/runAsync` will not be executed. ## Automatic mode The following example demonstrates the behavior of `ready` in automatic mode. Every time `ready` changes from `false` to `true`, the request will be executed. { setTimeout(() => { resolve('H' + Math.random().toString(36).substring(7)); }, 1000); }); } const Example = () => { const [ready, { toggle }] = useToggle(false); const { data, loading } = useRequest(getUsername, { ready, }); return ( <>

Ready: {JSON.stringify(ready)}

Username: {loading ? 'Loading' : data}

); }; export default Example;`} /> ## Manual mode The following example demonstrates the behavior of `ready` in manual mode. Only when `ready` is equal to `true`, `run` will be executed. { setTimeout(() => { resolve('H' + Math.random().toString(36).substring(7)); }, 1000); }); } const Example = () => { const [ready, { toggle }] = useToggle(false); const { data, loading, run } = useRequest(getUsername, { ready, manual: true, }); return ( <>

Ready: {JSON.stringify(ready)}

Username: {loading ? 'Loading' : data}

); }; export default Example;`} /> ## API ### Options | Property | Description | Type | Default | | -------- | ---------------------------- | --------- | ------- | | ready | Is the current request ready | `boolean` | `true` | # RefreshOnWindowFocus (/docs/useRequest/refresh-on-window-focus) # RefreshOnWindowFocus By setting `options.refreshOnWindowFocus`, the request will be refreshed when the browser is `refocus` and `revisible`. ```tsx | pure const { data } = useRequest(getUsername, { refreshOnWindowFocus: true, }); ``` You can click outside the browser, and then click the current page to experience the effect (or hide the current page and redisplay). If the interval from the previous request is greater than 5000ms, it will be requested again. { setTimeout(() => { resolve('H' + Math.random().toString(36).substring(7)); }, 1000); }); } const Example = () => { const { data, loading } = useRequest(getUsername, { refreshOnWindowFocus: true, }); return
Username: {loading ? 'Loading' : data}
; }; export default Example;`} /> ## API ### Options | Property | Description | Type | Default | | -------------------- | ------------------------------------------------------------------------ | --------- | ------- | | refreshOnWindowFocus | Whether to re-initiate the request when the screen refocus or revisible. | `boolean` | `false` | | focusTimespan | Re-request interval, in milliseconds | `number` | `5000` | ## Remark * `options.refreshOnWindowFocus`, `options.focusTimespan` support dynamic changes. * Listen for browser events `visibilitychange` and `focus`. # RefreshDeps (/docs/useRequest/refresy-deps) # RefreshDeps By setting `options.refreshDeps`, `useRequest` will run [refresh](https://ahooks.js.org/hooks/use-request/basic/#result) automatically when dependencies change, achieving the effect of [Refresh (repeat the last request)](https://ahooks.js.org/hooks/use-request/basic/#refresh-repeat-the-last-request). ```tsx | pure const [userId, setUserId] = useState('1'); const { data, run } = useRequest(() => getUserSchool(userId), { refreshDeps: [userId], }); ``` In the example code above, `useRequest` will execution when it is initialized and `userId` changes. It is exactly the same with the following implementation ```tsx | pure const [userId, setUserId] = useState('1'); const { data, refresh } = useRequest(() => getUserSchool(userId)); useEffect(() => { refresh(); }, [userId]); ``` ### Repeat last request { setTimeout(() => { resolve('H' + Math.random().toString(36).substring(7)); }, 1000); }); } const Example = () => { const [userId, setUserId] = useState(); const { data, loading, run } = useRequest((id: number) => getUsername(id), { refreshDeps: [userId], }); return (

Prev: {userId}

Username: {loading ? 'loading...' : data}

); }; export default Example;`} /> ### Custom refresh { setTimeout(() => { resolve('H' + Math.random().toString(36).substring(7)); }, 1000); }); } const Example = () => { const [userId, setUserId] = useState(); const { data, loading, run } = useRequest((id: number) => getUsername(id), { refreshDeps: [userId], refreshDepsAction: () => { if (typeof userId !== 'number') { console.log('userId is invalid, skip refresh'); return; } run(userId); }, }); return (

Prev: {userId}

Username: {loading ? 'loading...' : data}

); }; export default Example;`} /> ## API ### Options | Property | Description | Type | Default | | ----------------- | ------------------------------------------------------------------------------------------------------------- | ---------------------- | ------- | | refreshDeps | When the content of the array changes, trigger refresh. | `React.DependencyList` | `[]` | | refreshDepsAction | Customize the request behavior during dependency refresh; this parameter is invoked when dependencies change. | `() => void` | - | ## Remark * If you set `options.manual = true`, both `refreshDeps` and `refreshDepsAction` are no longer effective, you need to trigger the request by `run/runAsync`. # Error Retry (/docs/useRequest/retry) # Error Retry By setting `options.retryCount`, set the number of error retries, useRequest will retry after it fails. ```tsx | pure const { data, run } = useRequest(getUsername, { retryCount: 3, }); ``` As in the example code above, after the request is failed, it will retry 3 times. You can type text in the input box below and click the Edit button to experience the effect { setTimeout(() => { reject(new Error('Failed to modify username')); }, 1000); }); } const Example = () => { const [state, setState] = useState(''); const { loading, run } = useRequest(editUsername, { retryCount: 3, manual: true, onError: (error) => { console.error(error.message); }, }); return (
setState(e.target.value)} value={state} placeholder="Please enter username" style={{ width: 240, marginRight: 16 }} />
); }; export default Example;`} /> ## API ### Options | Property | Description | Type | Default | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- | | retryCount | The number of retries. If set to `-1`, it will try again indefinitely. | `number` | - | | retryInterval |
  • Retry interval in milliseconds.
  • If not set, the simple exponential backoff algorithm will be used by default, taking `1000 * 2 ** retryCount`, that is, waiting for 2s for the first retry, and 4s for the second retry. By analogy, if it is greater than 30s, take 30s
| `number` | - | ## Remark * `options.retryCount`, `options.retryInterval` support dynamic changes. * `cancel` can cancel the ongoing retry behavior. # Throttle (/docs/useRequest/throttle) # Throttle Enter the throttle mode by setting `options.throttleWait`. At this time, if `run` or `runAsync` is triggered frequently, the request will be executed with the throttle strategy. ```tsx | pure const { data, run } = useRequest(getUsername, { throttleWait: 300, manual: true }); ``` As in the example code above, if `run` is triggered frequently, it will only be executed once every 300ms. You can quickly enter text in the input box below to experience the effect { console.log('debounce getEmail', search); return new Promise((resolve) => { setTimeout(() => { resolve(Mock.mock({ 'data|5': ['@email'] }).data); }, 300); }); } const Example = () => { const { data, loading, run } = useRequest(getEmail, { throttleWait: 1000, manual: true, }); return (
run(e.target.value)} /> {loading ? (

loading

) : (
    {data?.map((i) => (
  • {i}
  • ))}
)}
); }; export default Example;`} /> ## API ### Options The usage and effects of all throttle property are the same as [lodash.throttle](https://lodash.com/docs/4.17.15#throttle) | Property | Description | Type | Default Value | | ---------------- | --------------------------------------------------------------------------- | --------- | ------------- | | throttleWait | Throttle wait time, in milliseconds. After setting, enter the throttle mode | `number` | - | | throttleLeading | Execute the request before throttling starts | `boolean` | `true` | | throttleTrailing | Execute the request after throttling ends | `boolean` | `true` | ## Remark * `options.throttleWait`, `options.throttleLeading`, `options.throttleTrailing` support dynamic changes. * `runAsync` will return a `Promise` when it is actually executed. When it is not executed, there will be no return. * `cancel` can abort a function waiting to be executed.