React Hooks 的分析 - useThrottle 系列 hooks
- Published on
- — 438 Words
- Authors
- Name
- Richard Shih
- @realshiddong
在 ahooks 中 useThrottle 系列包含了
- 一个状态管理 hook: useThrottle
- 两个副作用 hook: useThrottleFn 与 useThrottleEffect
与 useDebounce 系列的 hooks 一致,它们都是基于 useThrottleFn 所实现,而 useThrottleFn 又是基于 lodash 中封装的 throttle 实现,其入参、出参接口形式同 lodash/throttle.
这 3 个 hooks 的实现逻辑与 useDebounce 系列的实现逻辑完全一致,可以参考说明 React Hooks 的分析 - useDebounce 系列 hooks
useThrottleFn
其实现原理主要是调用 lodash 库中的 throttle 方法。
支持的 options 接口如下:
// useThrottle/throttleOptions.ts
export interface ThrottleOptions {
wait?: number
leading?: boolean
trailing?: boolean
}
主体的逻辑实现如下,与 useDebounceFn 封装方式如出一辙。
type noop = (...args: any[]) => any
function useThrottleFn<T extends noop>(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
// 调用 lodash 的节流函数
const throttled = useMemo(
() =>
throttle(
(...args: Parameters<T>): ReturnType<T> => {
return fnRef.current(...args)
},
wait,
options
),
[]
)
useUnmount(() => {
throttled.cancel()
})
return {
run: throttled,
cancel: throttled.cancel,
flush: throttled.flush,
}
}
export default useThrottleFn
useThrottleEffect
这个 hook 的功能是为 useEffect 增加节流的能力,实现方式与整体的执行流程与 useDebounceFn 一模一样,不需要多介绍了。
function useThrottleEffect(
effect: EffectCallback,
deps?: DependencyList,
options?: ThrottleOptions
) {
// 通过设置 flag 标识,flag 更新后会触发 useUpdateEffect 中的回调
const [flag, setFlag] = useState({})
const { run } = useThrottleFn(() => {
// 更新 flag
setFlag({})
}, options)
// 在 deps 数组中的某个依赖变化时,重新执行 run 函数
useEffect(() => {
return run()
}, deps)
// 只有在 flag 变化的时候,才执行 effect 回调逻辑
useUpdateEffect(effect, [flag])
}
export default useThrottleEffect
useThrottle
这个 hook 是用来处理节流值的。
function useThrottle<T>(value: T, options?: ThrottleOptions) {
const [throttled, setThrottled] = useState(value)
// 使用节流函数处理更新值
const { run } = useThrottleFn(() => {
setThrottled(value)
}, options)
useEffect(() => {
run()
}, [value])
return throttled
}
export default useThrottle