共计 2896 个字符,预计需要花费 8 分钟才能阅读完成。
源码链接: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;
}