From 047c481eb21c9c24de9e076b6b376b19d3143323 Mon Sep 17 00:00:00 2001 From: etctera Date: Thu, 30 Nov 2023 20:43:46 +0800 Subject: [PATCH] feat: useThrottle & useThrottleFn --- config/hooks.ts | 5 ++ packages/hooks/package.json | 2 +- packages/hooks/src/index.ts | 4 ++ .../hooks/src/useThrottle/example/example.tsx | 29 +++++++++++ packages/hooks/src/useThrottle/index.md | 38 ++++++++++++++ packages/hooks/src/useThrottle/index.ts | 19 +++++++ .../hooks/src/useThrottle/throttleOptions.ts | 5 ++ .../src/useThrottleFn/example/example.tsx | 29 +++++++++++ packages/hooks/src/useThrottleFn/index.md | 50 +++++++++++++++++++ packages/hooks/src/useThrottleFn/index.ts | 47 +++++++++++++++++ 10 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 packages/hooks/src/useThrottle/example/example.tsx create mode 100644 packages/hooks/src/useThrottle/index.md create mode 100644 packages/hooks/src/useThrottle/index.ts create mode 100644 packages/hooks/src/useThrottle/throttleOptions.ts create mode 100644 packages/hooks/src/useThrottleFn/example/example.tsx create mode 100644 packages/hooks/src/useThrottleFn/index.md create mode 100644 packages/hooks/src/useThrottleFn/index.ts diff --git a/config/hooks.ts b/config/hooks.ts index 6ae968f..a0115c2 100644 --- a/config/hooks.ts +++ b/config/hooks.ts @@ -24,6 +24,7 @@ export const menus = [ { title: 'useDebounce', link: '/hooks/use-debounce' }, { title: 'useResetState', link: '/hooks/use-reset-state' }, { title: 'useSet', link: '/hooks/use-set' }, + { title: 'useThrottle', link: '/hooks/use-throttle' }, { title: 'useToggle', link: '/hooks/use-toggle' }, { title: 'useUpdate', link: '/hooks/use-update' }, ], @@ -42,6 +43,10 @@ export const menus = [ title: 'useDebounceFn', link: '/hooks/use-debounce-fn', }, + { + title: 'useThrottleFn', + link: '/hooks/use-throttle-fn', + }, { title: 'useUpdateEffect', link: '/hooks/use-update-effect' }, ], }, diff --git a/packages/hooks/package.json b/packages/hooks/package.json index a92f007..7f49d75 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "etc-hooks", - "version": "0.4.9", + "version": "0.5.0", "description": "Etcetera React 业务 Hooks", "keywords": [ "etcetera", diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index 0e4e43a..e148c76 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -15,6 +15,8 @@ import useOs from './useOs' import useRequest from './useRequest' import useResetState from './useResetState' import useSet from './useSet' +import useThrottle from './useThrottle/index' +import useThrottleFn from './useThrottleFn/index' import useTitle from './useTitle' import useToggle from './useToggle' import useUnmount from './useUnmount' @@ -40,6 +42,8 @@ export { useRequest, useResetState, useSet, + useThrottle, + useThrottleFn, useTitle, useToggle, useUnmount, diff --git a/packages/hooks/src/useThrottle/example/example.tsx b/packages/hooks/src/useThrottle/example/example.tsx new file mode 100644 index 0000000..4d58e84 --- /dev/null +++ b/packages/hooks/src/useThrottle/example/example.tsx @@ -0,0 +1,29 @@ +/** + * title: Default usage + * desc: ThrottledValue will change every 500ms. + * + * title.zh-CN: 基础用法 + * desc.zh-CN: ThrottledValue 每隔 500ms 变化一次。 + */ + +import { Input } from 'antd' +import { useThrottle } from 'etc-hooks' +import React, { useState } from 'react' + +export default () => { + const [value, setValue] = useState() + const throttledValue = useThrottle(value, { wait: 500 }) + + return ( +
+ setValue(e.target.value)} + /> + +

throttledValue: {throttledValue}

+
+ ) +} diff --git a/packages/hooks/src/useThrottle/index.md b/packages/hooks/src/useThrottle/index.md new file mode 100644 index 0000000..4e3a93a --- /dev/null +++ b/packages/hooks/src/useThrottle/index.md @@ -0,0 +1,38 @@ +--- +nav: + path: /hooks +--- + +# useThrottle + +用来处理节流值的 Hook。 + +## 代码演示 + +### 基础用法 + + + +## API + +```typescript +const throttledValue = useThrottle( + value: any, + options?: Options +); +``` + +### Params + +| 参数 | 说明 | 类型 | 默认值 | +| ------- | -------------- | --------- | ------ | +| value | 需要节流的值 | `any` | - | +| options | 配置节流的行为 | `Options` | - | + +### Options + +| 参数 | 说明 | 类型 | 默认值 | +| -------- | ------------------------ | --------- | ------ | +| wait | 等待时间,单位为毫秒 | `number` | `1000` | +| leading | 是否在延迟开始前调用函数 | `boolean` | `true` | +| trailing | 是否在延迟开始后调用函数 | `boolean` | `true` | diff --git a/packages/hooks/src/useThrottle/index.ts b/packages/hooks/src/useThrottle/index.ts new file mode 100644 index 0000000..6262d69 --- /dev/null +++ b/packages/hooks/src/useThrottle/index.ts @@ -0,0 +1,19 @@ +import { useEffect, useState } from 'react' +import useThrottleFn from '../useThrottleFn' +import type { ThrottleOptions } from './throttleOptions' + +function useThrottle(value: T, options?: ThrottleOptions) { + const [throttled, setThrottled] = useState(value) + + const { run } = useThrottleFn(() => { + setThrottled(value) + }, options) + + useEffect(() => { + run() + }, [value]) + + return throttled +} + +export default useThrottle diff --git a/packages/hooks/src/useThrottle/throttleOptions.ts b/packages/hooks/src/useThrottle/throttleOptions.ts new file mode 100644 index 0000000..1c24650 --- /dev/null +++ b/packages/hooks/src/useThrottle/throttleOptions.ts @@ -0,0 +1,5 @@ +export interface ThrottleOptions { + wait?: number + leading?: boolean + trailing?: boolean +} diff --git a/packages/hooks/src/useThrottleFn/example/example.tsx b/packages/hooks/src/useThrottleFn/example/example.tsx new file mode 100644 index 0000000..a70755f --- /dev/null +++ b/packages/hooks/src/useThrottleFn/example/example.tsx @@ -0,0 +1,29 @@ +/** + * title: Default usage + * desc: Frequent calls run, but the function is only executed every 500ms. + * + * title.zh-CN: 基础用法 + * desc.zh-CN: 频繁调用 run,但只会每隔 500ms 执行一次相关函数。 + */ + +import { Button } from 'antd' +import { useThrottleFn } from 'etc-hooks' +import React, { useState } from 'react' + +export default () => { + const [value, setValue] = useState(0) + const { run } = useThrottleFn( + () => { + setValue(value + 1) + }, + { wait: 500 }, + ) + + return ( +
+

Clicked count: {value}

+ + +
+ ) +} diff --git a/packages/hooks/src/useThrottleFn/index.md b/packages/hooks/src/useThrottleFn/index.md new file mode 100644 index 0000000..2c880bc --- /dev/null +++ b/packages/hooks/src/useThrottleFn/index.md @@ -0,0 +1,50 @@ +--- +nav: + path: /hooks +--- + +# useThrottleFn + +用来处理函数节流的 Hook。 + +## 代码演示 + +### 基础用法 + + + +## API + +```typescript +const { + run, + cancel, + flush +} = useThrottleFn( + fn: (...args: any[]) => any, + options?: Options +); +``` + +### Params + +| 参数 | 说明 | 类型 | 默认值 | +| ------- | -------------- | ------------------------- | ------ | +| fn | 需要节流的函数 | `(...args: any[]) => any` | - | +| options | 配置节流的行为 | `Options` | - | + +### Options + +| 参数 | 说明 | 类型 | 默认值 | +| -------- | ------------------------ | --------- | ------ | +| wait | 等待时间,单位为毫秒 | `number` | `1000` | +| leading | 是否在延迟开始前调用函数 | `boolean` | `true` | +| trailing | 是否在延迟开始后调用函数 | `boolean` | `true` | + +### Result + +| 参数 | 说明 | 类型 | +| ------ | ---------------------------------- | ------------------------- | +| run | 触发执行 fn,函数参数将会传递给 fn | `(...args: any[]) => any` | +| cancel | 取消当前节流 | `() => void` | +| flush | 当前节流立即调用 | `() => void` | diff --git a/packages/hooks/src/useThrottleFn/index.ts b/packages/hooks/src/useThrottleFn/index.ts new file mode 100644 index 0000000..b945744 --- /dev/null +++ b/packages/hooks/src/useThrottleFn/index.ts @@ -0,0 +1,47 @@ +import { throttle } from 'lodash-es' +import { useMemo } from 'react' +import useLatest from '../useLatest' +import type { ThrottleOptions } from '../useThrottle/throttleOptions' +import useUnmount from '../useUnmount' +import { isFunction } from '../utils' +import isDev from '../utils/isDev' + +type noop = (...args: any[]) => any + +function useThrottleFn(fn: T, options?: ThrottleOptions) { + if (isDev) { + if (!isFunction(fn)) { + console.error( + `useThrottleFn expected parameter is a function, got ${typeof fn}`, + ) + } + } + + const fnRef = useLatest(fn) + + const wait = options?.wait ?? 1000 + + const throttled = useMemo( + () => + throttle( + (...args: Parameters): ReturnType => { + return fnRef.current(...args) + }, + wait, + options, + ), + [], + ) + + useUnmount(() => { + throttled.cancel() + }) + + return { + run: throttled, + cancel: throttled.cancel, + flush: throttled.flush, + } +} + +export default useThrottleFn