源码链接:https://github.com/alibaba/ho...
概述
首先,useDebounceFn和useDebounce都是一个用于增加防抖性能的hook,不同之处在于useDebounceFn给函数增加防抖,而useDebounce用来给值增加防抖。
防抖
某些时候,咱们会无法控制所编写事件的触发频率;比方搜索引擎的搜寻框对于输出内容的实时反馈,以及一些依据实时数据动静更新的组件。如果在短时间内触发大量事件,可能会引起闪动甚至卡顿。
防抖(Debounce)这个概念是解决此类问题的一种办法(其余的办法比方节流)。
防抖,管制事件只会在:触发该事件,并在固定工夫内未触发第二次时,才会执行。若短时间内该事件被间断触发屡次,则会在最初一次触发的固定工夫后再执行此事件。
useDebounceFn
该hook用来包装所须要的函数,给函数增加防抖动的性能。
简略用法
以下的代码将会在点击按钮并1000毫秒内未再次点击按钮时,将value变更为2。
import { useDebounceFn } from 'ahooks';import React, { useState } from 'react';export default () => { const [value, setValue] = useState(0); const { run } = useDebounceFn( (newValue) => { setValue(newValue); }, { wait: 1000, leading }, ); return ( <div> <p style={{ marginTop: 16 }}> Clicked count: {value} </p> <button type="button" onClick={run(2)}> chuange to 2 </button> </div> );};
参数阐明
配置参数
- wait:防抖等待时间,默认值为1000ms(number)
- leading:是否在提早开始前调用函数,默认为false
- trailing:是否在提早开始后调用函数,默认为true
- maxWait:最大等待时间,单位为ms
后果参数
- run:触发执行传入hook的函数,参数即为函数须要的参数
- cancel:勾销以后防抖
- flush:立刻调用以后防抖函数
源码剖析
isDev
if (isDev) { if (!isFunction(fn)) { console.error(`useDebounceFn expected parameter is a function, got ${typeof fn}`); } }
isDev是自定义的一个环境变量,用来判断以后是否处于开发环境。
useLatest
const fnRef = useLatest(fn);
useLatest也是ahooks的一个hook,个别是用来返回某个state的最新值,防止闭包问题(比方上一篇文章中提到过的,useCallback的闭包陷阱)。
debounce
const debounced = useMemo( () => debounce( (...args: Parameters<T>): ReturnType<T> => { return fnRef.current(...args); }, wait, options, ), [], );
debounce是lodash中的办法,用来解决包装函数解决防抖问题。这里应用useMemo缓存debounce这个办法,同样是为了缩小耗费。上面封装run、cancel、flush时,也是间接应用debounce的办法。
Parameters是typescript的告诫类型,用于获取函数T的参数类型,而ReturnType则是用来获取函数T的返回类型。
fnRef是应用useLatest封装好的,传入函数的最新值。
useUnmount
useUnmount(() => { debounced.cancel(); });
useUnmount也是ahooks封装好的hook,用来设置在组件卸载时执行的函数;为了避免内存泄露,当组件卸载时须要勾销对debounce的调用。
附上源码
import debounce from 'lodash/debounce';import { useMemo } from 'react';import type { DebounceOptions } from '../useDebounce/debounceOptions';import useLatest from '../useLatest';import useUnmount from '../useUnmount';import { isFunction } from '../utils';import isDev from '../utils/isDev';type noop = (...args: any[]) => any;function useDebounceFn<T extends noop>(fn: T, options?: DebounceOptions) {//判断是否开发环境 if (isDev) { if (!isFunction(fn)) { console.error(`useDebounceFn expected parameter is a function, got ${typeof fn}`); } } const fnRef = useLatest(fn); const wait = options?.wait ?? 1000; const debounced = useMemo( () => debounce( (...args: Parameters<T>): ReturnType<T> => { return fnRef.current(...args); }, wait, options, ), [], ); useUnmount(() => { debounced.cancel(); }); return { run: debounced, cancel: debounced.cancel, flush: debounced.flush, };}export default useDebounceFn;
useDebounce
剖析过useDebounceFn后,useDebounce的源码较为简单,间接用useState创立一个debounced,而后应用useDebounceFn封装它的更新办法setDebounced即可。
useEffect
该hook在每次依赖项扭转时会执行,与usecallback不同的是,当依赖项为空时,该hook每次从新渲染都会执行。用在这里,当传入的参数扭转时就调用一次debounce的run(当然还是遵循防抖动的规定)
源码
function useDebounce<T>(value: T, options?: DebounceOptions) { const [debounced, setDebounced] = useState(value); const { run } = useDebounceFn(() => { setDebounced(value); }, options); useEffect(() => { run(); }, [value]); return debounced;}